Sco*_*ord 7 python django transactions django-orm
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
Run Code Online (Sandbox Code Playgroud)
根据文档,我将确保重新引发正确的异常,您可以独立处理其他错误。对于 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
Run Code Online (Sandbox Code Playgroud)
这个例子将消除你的疑虑。
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.
Run Code Online (Sandbox Code Playgroud)
现在,如果您像这样引发自定义异常:
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.
Run Code Online (Sandbox Code Playgroud)