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

Goc*_*cht 27 python django transactions atomicity django-database

我正在尝试创建一个保存对象的视图,但是如果引发一些异常,我想撤消该保存.这是我试过的:

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
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?即使引发异常some_object仍然在DataBase中.

jlu*_*ier 34

原子文档

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

如果您发现异常,则需要自己处理:控制事务

如果您在发生故障时需要生成适当的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()
Run Code Online (Sandbox Code Playgroud)

  • 不,如果您想捕获异常,则必须在try..except块内使用“ with transaction.atomic”。我的观点是,您可以同时对视图使用@ transaction.atomic。如果您想使do_something()和try..except块的结果处于成功或失败的一个事务中,则这仍然有用。 (2认同)

jpi*_*pic 14

但是,如果一个例外饰有transaction.atomic功能情况,那么你没有什么做的,它会自动回滚到运行在你的函数之前,由装饰创建保存点,为记录:

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

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

    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
Run Code Online (Sandbox Code Playgroud)

此外,如果您想要更多控制,您可以手动回滚到先前设置的保存点,即:

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)
Run Code Online (Sandbox Code Playgroud)


Ant*_*ord 5

对我来说,这适用于 Django 2.2.5

首先在你的settings.py

...

DATABASES = {
    'default': {
        'ENGINE': 'xxx',  # transactional db
        ...
        'ATOMIC_REQUESTS': True,
    }
}
Run Code Online (Sandbox Code Playgroud)

在你的函数中(views.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
Run Code Online (Sandbox Code Playgroud)

  • 将“ATOMIC_REQUESTS”设置为“True”会使您的*所有*视图成为原子的 - 因此您应该将其设置为 true 并在要排除的视图上使用“@transaction.non_atomic_requests”,或者只是通过“单独将视图设置为原子” @transaction.atomic`。来源:https://docs.djangoproject.com/en/3.0/topics/db/transactions/#tying-transactions-to-http-requests (7认同)