[英]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.