Django原子事务和TransactionManagementError

时间:2016-03-10 18:38:16

标签: django

我有一个我想要的观点:
 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?

1 个答案:

答案 0 :(得分:2)

问题出现在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提供帮助的道具