簡體   English   中英

可以在 Django transaction.atomic() 中捕獲並重新引發異常嗎?

[英]Is it ok to catch and reraise an exception inside Django transaction.atomic()?

Django 的文檔是這樣說的關於transaction.atomic()和異常:

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

避免在 atomic 中捕獲異常!

退出原子塊時,Django 會查看它是正常退出還是異常退出,以確定是提交還是回滾。 如果您在原子塊內捕獲並處理異常,您可能會向 Django 隱藏發生問題的事實。 這可能會導致意外行為。

這主要是 DatabaseError 及其子類(例如 IntegrityError)的一個問題。 出現這樣的錯誤后,事務被破壞,Django 將在原子塊的末尾執行回滾。 如果您嘗試在回滾發生之前運行數據庫查詢,Django 將引發 TransactionManagementError。 當與 ORM 相關的信號處理程序引發異常時,您也可能會遇到此行為。

捕獲數據庫錯誤的正確方法是圍繞原子塊,如上所示。 如有必要,為此添加一個額外的原子塊。 這種模式還有另一個優點:它明確地界定了如果發生異常,哪些操作將被回滾。

如果您捕獲由原始 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 子句(您至少想要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.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM