【问题标题】:Django savepoint rollback on catching an Integrity Error causes a TransactionManagementErrorDjango 保存点回滚捕获完整性错误会导致 TransactionManagementError
【发布时间】:2016-11-18 07:57:31
【问题描述】:

我在 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.

【问题讨论】:

  • 请将完整的错误回溯添加到您的帖子中!这样我们就可以看到是哪个命令导致了问题。

标签: python django postgresql django-models transactions


【解决方案1】:

我认为您遇到了文档中描述的这个问题:

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

如那里所述,您可能想要执行transaction.set_rollback(False) 以防止整个原子块被回滚。

现在,您手动执行此操作是否有原因?您发布的代码可以使用嵌套的原子块完成同样的事情,并且如文档所述:

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

【讨论】:

    【解决方案2】:

    documentation 中所述:

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

    实现你想要的正确方法是创建另一个atomic 块:

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

    【讨论】:

      【解决方案3】:
      @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()
      

      请检查一下

      【讨论】:

        猜你喜欢
        • 2019-01-26
        • 1970-01-01
        • 1970-01-01
        • 2017-07-31
        • 2017-11-13
        • 1970-01-01
        • 2018-12-29
        • 2013-03-18
        • 2015-06-17
        相关资源
        最近更新 更多