【问题标题】:Django Atomic Transaction and TransactionManagementErrorDjango 原子事务和 TransactionManagementError
【发布时间】:2016-06-25 18:38:24
【问题描述】:

我有一个我想要的视图:
1. 保存模型实例
2. 可能保存更多模型实例

如果 1 或 2 有任何问题,则回滚 1 和 2。

无论我使用 transaction.savepoint() 还是使用嵌套的 transaction.atomic() 调用,我最终都会收到 TransactionManagementError。


查看 - 使用 transaction.savepoint()

@transaction.atomic
def my_view(request):
    foo = Foo()
    sid1 = transaction.savepoint()
    foo.save()
    if foo.whatever:
        error = 'blah'

    sid2 = transaction.savepoint()
    foo.create_saved_instances()  # creates more saved Foo instances in a separeate func
    if foo.something_else:
        error = 'baz'

    if error:
        transaction.savepoint_rollback(sid1) 
    else:
        transaction.savepoint_commit(sid2)

    ...


查看 - 使用 transaction.atomic()

@transaction.atomic
def my_view(request):
    foo = Foo()

    try:
        with transaction.atomic():
            foo.save()
            if foo.whatever:
                error = 'blah'

            try:
                with transaction.atomic():
                    foo.create_saved_instances()  # creates more saved Foo instances in a separeate func
                    if foo.something_else:
                        error = 'baz'
                    if error:
                        raise ValidationError
            except ValidationError:
                pass

            if error:
                raise ValidationError
    except ValidationError:
        pass

    ...

追溯

我使用 transaction.savepoint() 或 transaction.atomic() 得到一个 TransactionManagementError

下面是transaction.savepoint()的回溯

File ".../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File ".../lib/python2.7site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "...//project/users/decorators.py" in func
  64.                 return view_func(request, *args, **kwargs)

File ".../lib/python2.7site-packages/django/utils/decorators.py" in inner
  184.                     return func(*args, **kwargs)

File ".../project/employers/views/shiftcal.py" in my_view
  238.             transaction.savepoint_rollback(sid1)

File ".../lib/python2.7site-packages/django/db/transaction.py" in savepoint_rollback
  66.     get_connection(using).savepoint_rollback(sid)

File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in savepoint_rollback
  328.         self._savepoint_rollback(sid)

File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in _savepoint_rollback
  288.             cursor.execute(self.ops.savepoint_rollback_sql(sid))

File ".../lib/python2.7site-packages/djangodb/backends/utils.py" in execute
  79.             return super(CursorDebugWrapper, self).execute(sql, params)

File ".../lib/python2.7site-packages/django/db/backends/utils.py" in execute
  59.         self.db.validate_no_broken_transaction()

File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in validate_no_broken_transaction
  429.                 "An error occurred in the current transaction. You can't "

Exception Type: TransactionManagementError at /my-view/
Exception Value: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.


下面是 transaction.atomic() 的回溯

Traceback:

File "../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File ".../project/users/decorators.py" in func
  64.                 return view_func(request, *args, **kwargs)

File "../lib/python2.7/site-packages/django/utils/decorators.py" in inner
  184.                     return func(*args, **kwargs)

File "../project/employers/views/my_view.py" in my_view
  178.                         foo.create_saved_instances()

File "../project/jobs/models.py" in create_saved_instances
  2685.                     foo.save()

File "../project/jobs/models.py" in save
  2364.         super(Foo, self).save(*args, **kwargs)

File "../lib/python2.7/site-packages/django/db/models/base.py" in save
  700.                        force_update=force_update, update_fields=update_fields)

File "../lib/python2.7/site-packages/django/db/models/base.py" in save_base
  728.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

File "../lib/python2.7/site-packages/django/db/models/base.py" in _save_table
  812.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "../lib/python2.7/site-packages/django/db/models/base.py" in _do_insert
  851.                                using=using, raw=raw)

File "../lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
  122.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "../lib/python2.7/site-packages/django/db/models/query.py" in _insert
  1039.         return query.get_compiler(using=using).execute_sql(return_id)

File "../lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1060.                 cursor.execute(sql, params)

File "../lib/python2.7/site-packages/django/db/backends/utils.py" in execute
  79.             return super(CursorDebugWrapper, self).execute(sql, params)

File "../lib/python2.7/site-packages/django/db/backends/utils.py" in execute
  59.         self.db.validate_no_broken_transaction()

File "../lib/python2.7/site-packages/django/django/db/backends/base/base.py" in validate_no_broken_transaction
  429.                 "An error occurred in the current transaction. You can't "

Exception Type: TransactionManagementError at /my-view/
Exception Value: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.


有什么方法可以回滚所有事务而不出现 TransactionManagementError?

【问题讨论】:

  • 使用atomic的代码的回溯是什么。我认为您不应该手动引发IntegrityError,而是尝试引发不同的异常。
  • 最后我必须为 ajax 返回一个 HttpResponse(some_error, status=status) - 如果我创建一个错误,我会手动提出错误,以便可以轻松地将该错误传回,而不是返回一个错误字典(在我看来也有一个表格......它有点乱)
  • @Alasdair - 我添加了 transaction.atomic 的回溯 - 谢谢。
  • 回溯显示错误发生在create_saved_instances 方法中,但您还没有显示代码。该方法中是否有应该包装在原子块中的代码?
  • 看来你想通了。如果需要,您可以在 create_saved_instances 方法中捕获完整性错误,但如果您决定这样做,则应将 new_instance.save() 包装在另一个 transaction.atomic() 块中。这个想法在docs for atomic 中有解释(参见示例代码和注释)。

标签: django


【解决方案1】:

问题出在 foo.create_saved_instances() 中

def create_saved_instances():
    try:
        new_instance.save()
    except IntegrityError:
        pass

因此,IntegrityError 没有传播回嵌套的 transaction.atomic() 调用

try:    
    with transaction.atomic():
        foo.create_saved_instances()

因此在 foo.create_saved_instances() 中尝试了进一步的写入,从而引发了 TransactionManagementError。


向@Alasdair 提供帮助的道具

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    • 1970-01-01
    相关资源
    最近更新 更多