django数据库操作-数据库事务数据库事务

数据库事务

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

Django 提供多种方式控制数据库事务。

在调用试图方法前,Django 先生成一个事务。如果响应能正常生成,Django 会提交该事务。而如果视图出现异常,Django 则会回滚该事务。

你可以在你的视图代码中使用还原点执行子事务,一般会使用 atomic()上下文管理器。但是,在视图结束时,要么所有的更改都被提交,要么所有的更改都不被提交。

注意,只有视图被限制在事务中执行。中间件在事务之外运行,同理,渲染模板响应也是在事务之外运行的。

1、Django中使⽤事务说明

在保存订单数据中,涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败。

Django中对于数据库的事务,默认每执行一句数据库操作,便会自动提交。我们需要在保存订单中自己控制数据库事务的执行流程。

在Django中可以通过django.db.transaction模块提供的atomic来定义一个事务,atomic提供两种用法

  • 装饰器用法

    from django.db import transaction
    ​
    @transaction.atomic  # 一个出错就报错
    def viewfunc(request):
        # 这些代码会在一个事务中执行
        ...
    复制代码
  • with语句用法

    from django.db import transaction
    ​
    def viewfunc(request):
        # 这部分代码不在事务中,会被Django自动提交
        ...
    ​
        with transaction.atomic():
            # 这部分代码会在事务中执行
            ...
    复制代码

在Django中,还提供了保存点的支持,可以在事务中创建保存点来记录数据的特定状态,数据库出现错误时,可以恢复到数据保存点的状态

from django.db import transaction
​
# 创建保存点
save_id = transaction.savepoint()  
​
# 回滚到保存点
transaction.savepoint_rollback(save_id)
​
# 提交从保存点到当前状态的所有数据库事务操作
transaction.savepoint_commit(save_id)
复制代码

2、显式控制事务

atomic(using=None, savepoint=True)

原子性是数据库事务的定义属性。 atomic 允许创建代码块来保证数据库的原子性。如果代码块成功创建,这个变动会提交到数据库。如果有异常,变动会回滚。

atomic 块可以嵌套。在这个例子里,当内部块成功完成时,如果在稍后外部块里引发了异常,则仍可回滚到最初效果。

atomic 既可用作 decorator

方法一:

from django.db import transaction
​
@transaction.atomic
def viewfunc(request):
    do_stuff()
复制代码

方法二:

from django.db import transaction
​
def viewfunc(request):
    do_stuff()
​
    with transaction.atomic():
        do_more_stuff()
复制代码

方法三:

from django.db import IntegrityError, transaction
​
@transaction.atomic
def viewfunc(request):
    create_parent()
​
    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()
​
    add_children()
复制代码

提交后

需要执行与当前数据库事务相关的操作,但前提是事务成功提交。例子可能包含 Celery任务,邮件提醒或缓存失效。

Django提供on_commit()函数来注册成功提交事务后应执行的回调函数:

  • on_commit(func, using=None)

将任意函数(无参数)传递给 on_commit()

from django.db import transaction
​
def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.
​
transaction.on_commit(do_something)
复制代码

你也可以使用 lambda:: 包装函数

transaction.on_commit(lambda: some_celery_task.delay('arg1'))
复制代码

注意:事务提交成功后,才走异步任务