代码之家  ›  专栏  ›  技术社区  ›  melodibit

Django嵌套事务-带有事务。原子()--寻求澄清

  •  33
  • melodibit  · 技术社区  · 7 年前

    在里面 Django nested transactions - “with transaction.atomic()” 问题是,鉴于此。。。

    def functionA():
        with transaction.atomic():
            #save something
            functionB()
    
    def functionB():
        with transaction.atomic():
            #save another thing
    

    如果 functionB 失败并回滚,是否 functionA 也回滚?

    凯文·克里斯托弗·亨利(KevinChristopherHenry)回答道:“是的,如果任何一个函数发生异常,它们都将回滚。”然后他引用 the docs ,该状态:

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

    此文档引用似乎没有解决原始问题。医生说当 功能B )成功完成后,如果外部块(功能块)引发异常,仍可以回滚其效果。但问题是指相反的情况。问题是,如果内部块( 功能B )失败,是外部块( 功能性 )回滚?此文档引用不解决该场景。

    然而,在文档的下面,我们看到了这个示例。。。

    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() 仍然存在。

    如果我读对了医生的话 生成\u关系() (这类似于调用 功能B 在原始问题中)可以失败,并且在 create\u parent() 添加\u子项() 将提交到数据库。这似乎与凯文·克里斯托弗·亨利的答案相矛盾。

    令我困惑的是,我在 Django nested Transaction.atomic .

    我对Django和stackoverflow都是新手,所以我对自己阅读的文档没有太多信心,但这似乎与这两种回答都相矛盾。我想从更有经验的人那里得到一些澄清。非常感谢你。

    2 回复  |  直到 7 年前
        1
  •  56
  •   Kevin Christopher Henry    7 年前

    下面是一些带有嵌套事务块和数据库操作的伪代码 X , Y Z :

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

    如果 十、 引发一个异常,那么显然没有一个操作会有机会首先提交。

    如果 Y 引发一个异常,即您引用的问题,然后外部块也将回滚。这与嵌套事务本身没有任何关系,因为Python异常出现了。外部块将由异常退出,该异常总是导致回滚。不管是什么原因首先导致了异常,这都是事实。

    不明显的情况是 Z 引发了一个异常,这就是为什么文档需要特别注意的原因。像 referenced 二者都 十、 Y 将回滚:

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

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

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

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

    这与您提到的两个答案中的任何一个都不矛盾,因为这些答案解决了不涉及捕获任何异常的特定问题(带有代码示例)。

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

        2
  •  1
  •   iklinac    7 年前

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

    将原子封装在try/except块中可以自然处理 完整性错误

    基本上就是说,如果希望下面的块不引发外部事务回滚,只需尝试/捕获完整性错误

    正如您在文档中所述

    可以嵌套原子块。在这种情况下,当内部块 成功完成, 如果 稍后在外部块中引发异常 .

    因此,默认情况下,回滚将在错误传播时发生,第二个示例是一种使外部事务回滚静音的方法