可以在Django transaction.atomic()中捕获并重新获取异常吗?

时间:2017-03-03 19:21:53

标签: python django transactions django-orm

Django的文档说明了transaction.atomic()和例外:

https://docs.djangoproject.com/en/1.10/topics/db/transactions/#django.db.transaction.atomic

  

避免在原子内捕获异常!

     

当退出原子块时,Django会查看它是正常退出还是有异常来确定是提交还是回滚。如果你捕获并处理原子块中的异常,你可以向Django隐瞒问题已经发生的事实。这可能会导致意外行为。

     

这主要是DatabaseError及其子类(例如IntegrityError)的问题。发生这样的错误后,事务被破坏,Django将在原子块结束时执行回滚。如果您在回滚发生之前尝试运行数据库查询,Django将引发TransactionManagementError。当与ORM相关的信号处理程序引发异常时,您可能还会遇到此行为。

     

捕获数据库错误的正确方法是围绕原子块,如上所示。如有必要,为此目的添加额外的原子块。此模式具有另一个优点:它可以明确地分隔在发生异常时将回滚哪些操作。

     

如果捕获原始SQL查询引发的异常,则Django的行为未指定且与数据库有关。

这样做是否可行,或者这是否导致"意外行为"?

with transaction.atomic():
    # something
    try:
        # something
    except:
        logger.exception("Report error here.")
        raise

2 个答案:

答案 0 :(得分:1)

基于文档,我会确保重新引发正确的异常,以及您可能独立处理的其他错误。对于django,只需要在与数据库通信时获得有关出错的通知。

with transaction.atomic():
    # something
    try:
        # something
    except DatabaseError as db_err:
        logger.exception("Report error here.")
        raise db_err
    except Exception:
        # do something else
        # no need to reraise
        # as long as you handle it properly and db integrity is guaranteed

答案 1 :(得分:0)

  

这样做是否可行,或者这是否导致"意外行为"?

with transaction.atomic():
    # something
    try:
        # something
    except:
        logger.exception("Report error here.")
        raise

除了bare except子句(你至少想要except Exception:),这是好的,假设你的记录器没有触及数据库(这无论如何都是一个非常糟糕的主意)和记录器调用不会引发另一个异常(在这种情况下,我不知道实际会发生什么)。

但是你得到了相同的结果,反转transaction.atomic()块和try/except,即:

try:
    with transaction.atomic():
        # something
        # something
except Exception:
    logger.exception("Report error here.")
    raise