在Django nested transactions - “with transaction.atomic()”中,问题是,鉴于此......
def functionA():
with transaction.atomic():
#save something
functionB()
def functionB():
with transaction.atomic():
#save another thing
如果functionB
失败并回滚,functionA
也会回滚吗?
凯文克里斯托弗亨利回答说:“是的,如果任何一个功能发生异常,他们都会回滚。”然后他引用the docs,其中说明:
原子块可以嵌套。在这种情况下,当内部块成功完成时,如果稍后在外部块中引发异常,则仍然可以回滚其效果。
此文档引用似乎没有解决原始问题。文档说当INNER BLOCK(functionB
)成功完成时,如果OUTER块(函数A)引发异常,它的效果仍然可以回滚。但问题是相反的情况。问题是,INNER块(functionB
)FAILS是否是OUTER块(functionA
)回滚?该文档引用并未涉及该情况。
然而,在文档的下方我们看到了这个例子......
from django.db import IntegrityError, transaction
@transaction.atomic
def viewfunc(request):
create_parent()
try:
with transaction.atomic():
generate_relationships()
except IntegrityError:
handle_exception()
add_children()
......接着是这篇评论......
在此示例中,即使
generate_relationships()
通过破坏完整性约束导致数据库错误,您也可以在add_children()
中执行查询,而create_parent()
的更改仍然存在。
如果我正确地阅读了文档,则表示对generate_relationships()
的调用(类似于原始问题中对functionB
的调用)可能会失败并且{{1}中所做的更改}和create_parent()
将被提交到数据库。这似乎与Kevin Christopher Henry的回答相矛盾。
令我感到困惑的是,我在Django nested Transaction.atomic中看到了相同的问题/答案。
我是Django和stackoverflow的新手,所以我对阅读文档没有太多信心,但似乎与这两种反应都相矛盾。我正在寻找更有经验的人的澄清。非常感谢你。
答案 0 :(得分:14)
以下是一些嵌套事务块和数据库操作X
,Y
和Z
的伪代码:
with transaction.atomic():
X
with transaction.atomic():
Y
Z
如果X
引发异常,那么显然没有任何操作会有机会首先提交。
如果Y
引发异常 - 这是您引用的问题 - 那么外部块也将回滚。这与嵌套事务没有任何关系,本身就是因为Python异常冒泡而发生。外部块将被异常退出,该异常总是导致回滚。无论什么原因造成例外,这都是正确的。
不明显的情况是当Z
引发异常时会发生什么,以及文档为什么要特别注意它的原因。在referenced时,X
和Y
都将被回滚:
当内部块成功完成时,如果稍后在外部块中引发异常,则仍然可以回滚其效果。
现在,它也可以捕获嵌套操作引发的异常。
with transaction.atomic():
X
try:
with transaction.atomic():
Y
except IntgrityError:
pass
Z
在这种情况下,如果Y
抛出异常,内部块将被回滚(因为它以异常退出)但外部块不会被激活(因为它不会)。
这与您提到的两个答案中的任何一个中的信息都不矛盾,因为那些答案中没有涉及特定问题(使用代码示例)并不涉及任何例外。
无论如何,感谢您提供反馈并有机会提供更全面的答案。
答案 1 :(得分:1)
第二个示例是捕获IntegrityError,因此外部事务原子不会意识到发生以下错误
在try / except块中包装原子允许自然处理 完整性错误
基本上说如果你想要跟随块不要引发外部事务回滚只是尝试/捕获完整性错误
正如您已从文档中说明以下内容
原子块可以嵌套。在这种情况下,当一个内部块 成功完成,如果,其效果仍然可以回滚 稍后在外部区块中引发异常。
因此,默认情况下会发生回滚,因为错误会传播,第二个示例是静默外部事务回滚的方法