捕获完整性错误的Django保存点回滚会导致TransactionManagementError

时间:2016-11-18 07:57:32

标签: python django postgresql django-models transactions

我在Django的transaction.atomic块中运行以下代码。

@transaction.atomic()
def test():
   a.save()
   sid = transaction.savepoint()
   try:
       b.save()
       transaction.savepoint_commit(sid)
   except IntegrityError as e:
       transaction.savepoint_rollback(sid)
   c.save()

此代码给出了以下错误 -

TransactionManagementError
An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

我按照官方文档中的以下链接进行操作。 https://docs.djangoproject.com/en/1.10/topics/db/transactions/#s-savepoint-rollback

我在这里缺少什么?

编辑: - 添加堆栈跟踪。

    File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/models/manager.py", line 122, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/models/query.py", line 401, in create
    obj.save(force_insert=True, using=self.db)
  File "/Users/vibhor/Documents/juggernaut/user-persistence-service/books/models/books.py", line 243, in save
    transaction.savepoint_rollback(sid)
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/transaction.py", line 66, in savepoint_rollback
    get_connection(using).savepoint_rollback(sid)
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/backends/base/base.py", line 328, in savepoint_rollback
    self._savepoint_rollback(sid)
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/backends/base/base.py", line 288, in _savepoint_rollback
    cursor.execute(self.ops.savepoint_rollback_sql(sid))
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/backends/utils.py", line 59, in execute
    self.db.validate_no_broken_transaction()
  File "/Users/vibhor/Documents/juggernaut/user-venv-new/lib/python2.7/site-packages/django/db/backends/base/base.py", line 429, in validate_no_broken_transaction
    "An error occurred in the current transaction. You can't "
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

3 个答案:

答案 0 :(得分:1)

我认为你正在遇到文档中描述的这个问题:

  

可以使用保存点通过执行部分回滚来从数据库错误中恢复。如果你在atomic()块内执行此操作,整个块仍将被回滚,因为它不知道你已经处理了较低级别的情况!为防止这种情况,您可以使用以下函数控制回滚行为...

如前所述,您可能希望执行transaction.set_rollback(False)以防止整个原子块被回滚。

现在,您是否有理由手动执行此操作?您发布的代码可以使用嵌套的原子块完成相同的操作,并且文档说明:

  

atomic()装饰器嵌套时,它会创建一个保存点以允许部分提交或回滚。强烈建议您使用atomic()而不是下面描述的功能。

答案 1 :(得分:1)

正如documentation

中所述
  

为了保证原子性,atomic会禁用某些API。尝试在原子块中提交,回滚或更改数据库连接的自动提交状态将引发异常。

实现目标的正确方法是创建另一个atomic块:

@transaction.atomic()
def test():
   a.save()
   try:
       with transaction.atomic():
           b.save()
   except IntegrityError:
       #handle exception here...
       ...
   c.save()

答案 2 :(得分:-1)

@transaction.atomic()
def test():
   a.save()
   sid = transaction.savepoint()
   try:
       with transaction.atomic():
           b.save()
           transaction.savepoint_commit(sid)
   except IntegrityError as e:
       transaction.savepoint_rollback(sid)
   c.save()

请检查