From: <gre...@mi...> - 2008-04-24 14:44:12
|
Spring Python users, I have recently made some additions to Spring Python, and just committed them to the trunk. You can now mark up classes with @Transactional and pick your propagation level of support. This allows you to define which methods need transactions, which ones will work within existing transactions, and which ones will NOT. For example, here is a sample bank application. Each method is marked @Transactional, and with different propagation levels. When this class is injected into a DecoratorBasedApplicationContext, and there is defined an AutoTransactionalComponent, the methods are activated to work transactionally! I'm still trying to figure out how to utilize isolation level. Different databases support this differently, and it is not currently part of Python's DB API 2.0 spec. If I can't find a quick solution, I will make a release of the current features soon. Let me know if this is useful to you, and also let me know if you run into any issues. Good luck! To get this release, see https://svn.springpython.webfactional.com/trunk. class TransactionalBankWithLotsOfTransactionalArguments(object): """This sample application can be used to demonstrate the value of atomic operations. The transfer operation must be wrapped in a transaction in order to perform correctly. Otherwise, any errors in the deposit will allow the from-account to leak assets.""" def __init__(self, factory): self.logger = logging.getLogger("springpython.test.testSupportClasses.TransactionalBankWithLotsOfTransactionalArguments") self.dt = DatabaseTemplate(factory) @Transactional(["PROPAGATION_REQUIRED"]) def open(self, accountNum): self.logger.debug("Opening account %s with $0 balance." % accountNum) self.dt.execute("INSERT INTO account (account_num, balance) VALUES (?,?)", (accountNum, 0)) @Transactional(["PROPAGATION_REQUIRED"]) def deposit(self, amount, accountNum): self.logger.debug("Depositing $%s into %s" % (amount, accountNum)) rows = self.dt.execute("UPDATE account SET balance = balance + ? WHERE account_num = ?", (amount, accountNum)) if rows == 0: raise BankException("Account %s does NOT exist" % accountNum) @Transactional(["PROPAGATION_REQUIRED"]) def withdraw(self, amount, accountNum): self.logger.debug("Withdrawing $%s from %s" % (amount, accountNum)) rows = self.dt.execute("UPDATE account SET balance = balance - ? WHERE account_num = ?", (amount, accountNum)) if rows == 0: raise BankException("Account %s does NOT exist" % accountNum) return amount @Transactional(["PROPAGATION_SUPPORTS","readOnly"]) def balance(self, accountNum): self.logger.debug("Checking balance for %s" % accountNum) return self.dt.queryForObject("SELECT balance FROM account WHERE account_num = ?", (accountNum,), types.FloatType) @Transactional(["PROPAGATION_REQUIRED"]) def transfer(self, amount, fromAccountNum, toAccountNum): self.logger.debug("Transferring $%s from %s to %s." % (amount, fromAccountNum, toAccountNum)) self.withdraw(amount, fromAccountNum) self.deposit(amount, toAccountNum) @Transactional(["PROPAGATION_NEVER"]) def nonTransactionalOperation(self): self.logger.debug("Executing non-transactional operation.") @Transactional(["PROPAGATION_MANDATORY"]) def mandatoryOperation(self): self.logger.debug("Executing mandatory transactional operation.") @Transactional(["PROPAGATION_REQUIRED"]) def mandatoryOperationTransactionalWrapper(self): self.mandatoryOperation() self.mandatoryOperation() @Transactional(["PROPAGATION_REQUIRED"]) def nonTransactionalOperationTransactionalWrapper(self): self.nonTransactionalOperation() class DatabaseTxTestDecorativeTransactionsWithLotsOfArguments(DecoratorBasedApplicationContext): def __init__(self, factory): self.factory = factory DecoratorBasedApplicationContext.__init__(self) @component def transactionManager(self): return ConnectionFactoryTransactionManager(self.factory) @component def transactionalComponent(self): return AutoTransactionalComponent(self.transactionManager()) @component def bank(self): results = TransactionalBankWithLotsOfTransactionalArguments(self.factory) return results |