gpt4 book ai didi

django - 在 Django 中使用嵌套的 @transaction.commit_on_success

转载 作者:行者123 更新时间:2023-12-04 14:47:02 29 4
gpt4 key购买 nike

考虑这个简单的例子:

# 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)

如果在 Account.add() 中引发异常,交易在 Account.withdraw()仍然会被提交并且会损失金钱,因为 Django 当前不处理嵌套事务。

不给django打补丁,如何保证commit被发送到数据库,但是只有在 @transaction.commit_on_success下的main函数才生效装饰器完成而不引发异常?

我遇到了这个片段: http://djangosnippets.org/snippets/1343/它似乎可以完成这项工作。如果我使用它,有什么我应该注意的缺点吗?

如果您能提供帮助,在此先非常感谢。

附言为了可见性,我正在复制之前引用的代码片段:
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)

最佳答案

这段代码的问题在于它不能让您在不回滚外部事务的情况下回滚内部事务。例如:

@nested_commit_on_success
def inner():
# [do stuff in the DB]

@nested_commit_on_success
def outer():
# [do stuff in the DB]
try:
inner()
except:
# this did not work, but we want to handle the error and
# do something else instead:

# [do stuff in the DB]

outer()

在上面的例子中,即使 inner()引发异常,其内容不会回滚。

您需要的是一个 savepoint对于内部“交易”。对于您的代码,它可能如下所示:
# a bank account class
class Account:
def withdraw(self, amount):
sid = transaction.savepoint()
try:
# code to withdraw money from the account
except:
transaction.savepoint_rollback(sid)
raise

def add(self, amount):
sid = transaction.savepoint()
try:
# code to add money to the account
except:
transaction.savepoint_rollback(sid)
raise

# somewhere else
@transaction.commit_on_success
def makeMoneyTransaction(src_account, dst_account, amount):
src_account.withdraw(amount)
dst_account.add(amount)

从 Django 1.6 开始, atomic()装饰器正是这样做的:它为装饰器的外部使用使用一个事务,任何内部使用都使用一个保存点。

关于django - 在 Django 中使用嵌套的 @transaction.commit_on_success,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14832579/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com