Django嵌套事务 - “与transaction.atomic()” - 寻求澄清

时间:2018-02-16 21:45:49

标签: sql django transactions

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的新手,所以我对阅读文档没有太多信心,但似乎与这两种反应都相矛盾。我正在寻找更有经验的人的澄清。非常感谢你。

2 个答案:

答案 0 :(得分:14)

以下是一些嵌套事务块和数据库操作XYZ的伪代码:

with transaction.atomic():
    X
    with transaction.atomic():
        Y
    Z

如果X引发异常,那么显然没有任何操作会有机会首先提交。

如果Y引发异常 - 这是您引用的问题 - 那么外部块也将回滚。这与嵌套事务没有任何关系,本身就是因为Python异常冒泡而发生。外部块将被异常退出,该异常总是导致回滚。无论什么原因造成例外,这都是正确的。

不明显的情况是当Z引发异常时会发生什么,以及文档为什么要特别注意它的原因。在referenced时,XY都将被回滚:

  

当内部块成功完成时,如果稍后在外部块中引发异常,则仍然可以回滚其效果。

现在,它也可以捕获嵌套操作引发的异常。

with transaction.atomic():
    X
    try:
        with transaction.atomic():
            Y
    except IntgrityError:
        pass
    Z

在这种情况下,如果Y抛出异常,内部块将被回滚(因为它以异常退出)但外部块不会被激活(因为它不会)。

这与您提到的两个答案中的任何一个中的信息都不矛盾,因为那些答案中没有涉及特定问题(使用代码示例)并不涉及任何例外。

无论如何,感谢您提供反馈并有机会提供更全面的答案。

答案 1 :(得分:1)

第二个示例是捕获IntegrityError,因此外部事务原子不会意识到发生以下错误

  

在try / except块中包装原子允许自然处理   完整性错误

基本上说如果你想要跟随块不要引发外部事务回滚只是尝试/捕获完整性错误

正如您已从文档中说明以下内容

  

原子块可以嵌套。在这种情况下,当一个内部块   成功完成,如果,其效果仍然可以回滚   稍后在外部区块中引发异常

因此,默认情况下会发生回滚,因为错误会传播,第二个示例是静默外部事务回滚的方法