Django:正确处理IntegrityError的方法
如何正确处理IntegrityError
或其他可能导致事务混乱的错误,而不使用手动事务控制?
在我的应用程序中,我遇到了IntegrityError
的问题,我想要解决这些问题,因为它们会影响后续的数据库操作,导致我遇到:
DatabaseError: current transaction is aborted, commands ignored until end of transaction block`
在忽略IntegrityErrors
后,所有的数据库活动都会受到影响。
这段代码应该能重现我遇到的错误
from django.db import transaction
try:
MyModel.save() # Do a bad save that will raise IntegrityError
except IntegrityError:
pass
MyModel.objects.all() # raises DatabaseError: current transaction is aborted, commands ignored until end of transaction block
根据文档,解决IntegrityError
的方法是回滚事务。但是,下面的代码却导致了TransactionManagementError
。
from django.db import transaction
try:
MyModel.save()
except IntegrityError:
transaction.rollback() # raises TransactionManagementError: This code isn't under transaction management
MyModel.objects.all() # Should work
编辑:我对TransactionManagementError
的提示感到困惑,因为如果在我的except
中我执行:
connection._cursor().connection.rollback()
而不是使用django的transaction.rollback()
,那么MyModel.objects.all()
就能成功,这让我觉得很奇怪,如果我的代码“没有在事务管理之下”。而且,似乎也不合理的是,未在事务管理之下的代码(我认为这意味着它在使用自动提交)却可以有跨多个查询的事务。
编辑 #2:我知道可以使用手动事务控制来处理这些错误,但难道我不应该能够在不使用手动事务控制的情况下恢复吗?我理解的是,如果我使用自动提交,每个事务应该只有一次写入,所以这不应该影响后续的数据库活动。
编辑 #3:这是几年前的事了,但在django 1.4(不确定后续版本)中,另一个问题是Model.objects.bulk_create()
并不遵循自动提交的行为。
版本:
- Django: 1.4 (
TransactionMiddleWare
未启用) - Python: 2.7
- Postgres: 9.1
1 个回答
3
Django默认的提交模式是自动提交(AutoCommit)。如果你想要进行回滚操作,就需要把执行工作的代码放在一个事务中。 [文档]
with transaction.commit_on_success():
# Your code here. Errors will auto-rollback.
要实现数据库级别的自动提交,你需要在你的DATABASES设置字典中添加以下选项。
'OPTIONS': {'autocommit': True,}
另外,你也可以使用明确的保存点来进行回滚。 [文档]
@transaction.commit_manually
def viewfunc(request):
a.save()
# open transaction now contains a.save()
sid = transaction.savepoint()
b.save()
# open transaction now contains a.save() and b.save()
if want_to_keep_b:
transaction.savepoint_commit(sid)
# open transaction still contains a.save() and b.save()
else:
transaction.savepoint_rollback(sid)
# open transaction now contains only a.save()
transaction.commit()