Django-使用事务原子回滚保存

问题描述 投票:26回答:3

我正在尝试创建一个保存对象的视图,但是我想undo在出现异常时进行保存。这是我尝试过的:

class MyView(View):

    @transation.atomic
    def post(self, request, *args, **kwargs):
        try:
            some_object = SomeModel(...)
            some_object.save()

            if something:
                raise exception.NotAcceptable()
                # When the workflow comes into this condition, I think the previous save should be undome
                # Whant am I missing?

        except exception.NotAcceptable, e:
            # do something

我在做什么错?即使引发异常,some_object仍在数据库中。

python django transactions atomicity django-database
3个回答
32
投票

Atomicity Documentation

总而言之,如果视图产生没有错误的响应,则@transaction.atomic将在数据库上执行事务。因为您自己正在捕获异常,所以在Django中,您的视图执行得很好。

如果发现异常,则需要自己处理:Controlling Transactions

如果失败时需要产生适当的json响应:

from django.db import SomeError, transaction

def viewfunc(request):
    do_something()

    try:
        with transaction.atomic():
            thing_that_might_fail()
    except SomeError:
        handle_exception()

    render_response()

14
投票

但是,如果在用transaction.atomic装饰的函数中发生异常,那么您就无事可做,它会以rollback automatically to the savepoint created by the decorator before running the your function的形式显示为documented

atomic允许我们创建一个代码块,在其中保证数据库的原子性。如果代码块成功完成,则更改将提交给数据库。如果有异常,则更改将回滚。

如果异常被捕获在except块中,则应重新引发它以使atomic捕获并执行回滚,即:

    try:
        some_object = SomeModel(...)
        some_object.save()

        if something:
            raise exception.NotAcceptable()
            # When the workflow comes into this condition, I think the previous save should be undome
            # Whant am I missing?

    except exception.NotAcceptable, e:
        # do something
        raise  # re-raise the exception to make transaction.atomic rollback

此外,如果需要更多控制权,则可以手动回滚到previously set savepoint,即:

class MyView(View):
    def post(self, request, *args, **kwargs):
        sid = transaction.savepoint()
        some_object = SomeModel(...)
        some_object.save()

        if something:
            transaction.savepoint_rollback(sid)
        else:
            try:
                # In worst case scenario, this might fail too
                transaction.savepoint_commit(sid)
            except IntegrityError:
                transaction.savepoint_rollback(sid)

0
投票

对我来说,这在Django 2.2.5中有效

首先是您的setting.py

...

DATABASES = {
    'default': {
        'ENGINE': 'xxx',  # transactional db
        ...
        'ATOMIC_REQUESTS': True,
    }
}

并且在您的函数中(view.py)

from django.db import transaction

@transaction.atomic
def make_db_stuff():

    # do stuff in your db (inserts or whatever)

    if success:
        return True
    else:
        transaction.set_rollback(True)
        return False
© www.soinside.com 2019 - 2024. All rights reserved.