この簡単な例を考えてみましょう:
# a bank account class
class Account:
@transaction.commit_on_success
def withdraw(self, amount):
# code to withdraw money from the account
@transaction.commit_on_success
def add(self, amount):
# code to add money to the account
# somewhere else
@transaction.commit_on_success
def makeMoneyTransaction(src_account, dst_account, amount):
src_account.withdraw(amount)
dst_account.add(amount)
( https://code.djangoproject.com/ticket/2227から取得)
で例外が発生した場合、 Django は現在ネストされたトランザクションを処理しないためAccount.add()
、 のトランザクションAccount.withdraw()
は引き続きコミットされ、お金が失われます。
Django にパッチを適用せずに、コミットがデータベースに送信されるようにするにはどうすればよい@transaction.commit_on_success
でしょうか。ただし、例外を発生させずにデコレータの下のメイン関数が終了した場合のみです。
私はこのスニペットに出くわしました: http://djangosnippets.org/snippets/1343/そしてそれは仕事をすることができるようです. 使用する上で注意すべきデメリットはありますか?
ご協力いただける場合は、事前に多大な感謝を申し上げます。
PS可視性のために、以前に引用したコードスニペットをコピーしています。
def nested_commit_on_success(func):
"""Like commit_on_success, but doesn't commit existing transactions.
This decorator is used to run a function within the scope of a
database transaction, committing the transaction on success and
rolling it back if an exception occurs.
Unlike the standard transaction.commit_on_success decorator, this
version first checks whether a transaction is already active. If so
then it doesn't perform any commits or rollbacks, leaving that up to
whoever is managing the active transaction.
"""
commit_on_success = transaction.commit_on_success(func)
def _nested_commit_on_success(*args, **kwds):
if transaction.is_managed():
return func(*args,**kwds)
else:
return commit_on_success(*args,**kwds)
return transaction.wraps(func)(_nested_commit_on_success)