As I see in the transaction.py, commit()/rollback() call connection._commit()/connection._rollback() explicitly.
It breaks the case when a function with commit_manually or commit_on_success decorator calls another function decorated the same way (enters the transaction management).
Consider following scenario:
# a bank account class
class Account:
@transaction.commit_on_success
def withdraw(self, sum):
# code to withdraw money from the account
@transaction.commit_on_success
def add(self, sum):
# code to add money to the account
# somewhere else
@transaction.commit_on_success
def makeMoneyTransaction(from_account, to_account, sum):
# this code will call commit on success
from_account.withdraw(sum)
# this code may raise an exception, and if it raises,
# commit won't be called in Account.add() and makeMoneyTransaction()
# But money had been already withdrawn, and the from_account saved in the database.
# The makeMoneyTransaction's transaction is inconsistent.
# So we loose our money
to_account.add(sum)
IMO, what the transaction.commit should do in this case is to check first whether the transaction is "nested".
In the AdoDB PHP library, each call to StartTrans? either starts new transaction or increments the counter of the nested StartTrans? calls. CompleteTrans? either calls commit/rollback (if its StartTrans? counterpart was not called inside another StartTrans/CompleteTrans? block) or decrements the counter.
I rate this deficiency as major. What do you think?