可以在django Transaction.Atomic()中捕获和Reraise一个例外吗?



django的文档对transaction.atomic()和例外说:

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

避免在Atomic内部捕获异常!

退出原子块时,Django查看它是正常退出还是以外的例外,以确定是否提交还是回滚。如果您在原子块中捕获并处理异常,则可能会从Django隐藏问题。这可能导致出乎意料的行为。

这主要是数据库及其子类(例如IntegrityError)的关注点。发生这种错误后,交易被打破,Django将在原子块的末端进行回滚。如果您尝试在回滚发生之前运行数据库查询,Django将筹集交易ManagementError。当与ORM相关的信号处理程序引起例外时,您也可能会遇到此行为。

如上所示,捕获数据库错误的正确方法是在原子块附近。如有必要,为此目的添加一个额外的原子块。该模式具有另一个优势:它明确划定了如果发生例外,将回滚哪些操作。

如果您发现了由RAW SQL查询提出的异常,则Django的行为是未指定的,并且依赖数据库。

可以做到这一点,或者这会导致"意外行为"?

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

基于文档,我将确保重新提出正确的异常,其他您可能会独立处理的错误。对于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

可以执行此操作还是会导致"意外行为"?

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

除了裸露的子句(至少要except Exception:),这是可以的,假设您的记录器没有触摸数据库(无论如何这是一个非常糟糕的主意),并且记录器调用不会引起另一个异常(在这种情况下,我不知道会发生什么)。

,但是您会得到相同的结果,即transaction.atomic()块和try/except,即:

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

此示例将清除您的疑问。

with transaction.atomic():
    try:
        # if you do something that raises ONLY db error. ie. Integrity error
    except Exception:
        # and you catch that integrity error or any DB error like this here.
        # now if you try to update your DB
        model = Model.objects.get(id=1)
        model.description = "new description"
        model.save()
        # This will be illegal to do and Django in this case 
        # will raise TransactionManagementError suggesting 
        # you cannot execute any queries until the end of atomic block.

现在,如果您提高了这样的自定义例外:

with transaction.atomic():
    try:
        # raising custom exception
        raise Exception("some custom exception")
    except Exception:
        # and you catch that exception here
        # now if you try to update your DB
        model = Model.objects.get(id=1)
        model.description = "new description"
        model.save()
        # Django will allow you to update the DB.

最新更新