首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Django嵌套事务--“with transaction.atomic()”--寻求澄清

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

Stack Overflow用户
提问于 2018-02-16 21:45:49
回答 2查看 5.6K关注 0票数 35

Django嵌套事务--“with transaction.atomic()”,问题是,考虑到这一点.

代码语言:javascript
运行
复制
def functionA():
    with transaction.atomic():
        #save something
        functionB()

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

如果functionB失败并回滚,functionA也会回滚吗?

回答道:“是的,如果在任何一个函数中出现异常,它们都会被回滚。”然后,他引用医生们的话说:

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

这个文档引用似乎没有解决原来的问题。文档是说,当内部块(即functionB)成功完成时,如果外部块(即functionA)引发异常,它的效果仍然可以回滚。但问题是相反的情况。问题是,如果内部块(functionB)失败,外部块(functionA)是否回滚?这个文档引用并不能解决这种情况。

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

代码语言:javascript
运行
复制
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()

...followed通过这篇评论..。

在本例中,即使generate_relationships()通过打破完整性约束导致数据库错误,您也可以在add_children()中执行查询,而来自create_parent()的更改仍然存在。

如果我正确地阅读了文档,这意味着对generate_relationships()的调用(类似于原始问题中对functionB的调用)可能失败,create_parent()add_children()中所做的更改将提交到数据库中。这似乎与凯文·克里斯托弗·亨利的回答相矛盾。

令我费解的是,我在Django嵌套Transaction.atomic中看到了同样的问题/答案。

我对Django和stackoverflow都很陌生,所以我对我对文档的阅读没有很大的信心,但这似乎与这两种反应相矛盾。我在找一个更有经验的人澄清。非常感谢你。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-17 00:00:34

下面是一些带有嵌套事务块和数据库操作( XYZ )的伪代码

代码语言:javascript
运行
复制
with transaction.atomic():
    X
    with transaction.atomic():
        Y
    Z

如果X引发异常,那么很明显,任何操作都不会首先获得提交的机会。

如果Y引发异常--这是您所引用的问题--那么外部块也会回滚。这与嵌套事务本身没有任何关系,发生这种情况是因为Python异常出现了气泡。外部块将被异常退出,这通常会导致回滚。不管是什么导致了异常,这都是正确的。

不明显的情况是,当Z引发异常时会发生什么,这就是为什么文档需要特别注意的原因。作为参考XY都将被回滚:

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

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

代码语言:javascript
运行
复制
with transaction.atomic():
    X
    try:
        with transaction.atomic():
            Y
    except IntgrityError:
        pass
    Z

在本例中,如果Y抛出异常,内部块将被回滚(因为它与异常一起退出),但外部块不会(因为它没有)。

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

无论如何,谢谢你的反馈和给出一个更全面的答案的机会。

票数 59
EN

Stack Overflow用户

发布于 2018-02-16 22:18:36

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

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

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

正如您在文档中已经指出的那样

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

因此,在默认情况下,回滚将随着错误的传播而发生,第二个示例是使外部事务回滚保持沉默的一种方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48835309

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档