Django中的事务

1 开启全局的事务

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql',  # 使用mysql数据库
        'NAME': 'tracerbackend',  # 要连接的数据库
        'USER': 'root',  # 链接数据库的用于名
        'PASSWORD': '123456',  # 链接数据库的用于名
        'HOST': '192.168.1.200',  # mysql服务监听的ip
        'PORT': 3306,  # mysql服务监听的端口
        # 设置为True代表同一个http请求所对应的所有sql都放在一个事务中执行
        # (要么所有都成功,要么所有都失败),这是全局性的配置,如果要对某个
        # http请求放水(然后自定义事务),可以用non_atomic_requests修饰器
        'ATOMIC_REQUESTS': True,
    }
}

在Django中,'ATOMIC_REQUESTS': True 是一个数据库设置选项,它会在每个HTTP请求开始时自动开启一个数据库事务,并在请求结束时提交或回滚该事务。这提供了一种方便的方式来确保数据库操作的原子性,即要么全部成功,要么全部失败。

# 设置中默认开启全局事务
def home(request):
    models.Module.objects.create(project_id=1, title="测试事务")
    1/0
    models.IssuesType.objects.create(project_id=1, title="测试事务")
    return render(request, "home.html")

在这个例子中,我们为默认的数据库连接设置了'ATOMIC_REQUESTS': True。这意味着每当Django处理一个HTTP请求时,它都会自动开启一个数据库事务。如果请求成功完成并且没有发生任何异常,那么事务会在请求结束时自动提交。如果请求期间发生了异常,那么事务会被回滚,从而撤销该请求所做的所有数据库更改。

from django.db import transaction
# 局部禁用
@transaction.non_atomic_requests
def home(request):
    models.Module.objects.create(project_id=1, title="测试事务")
    1/0
    models.IssuesType.objects.create(project_id=1, title="测试事务")
    return render(request, "home.html")

注意事项

  • 性能:虽然'ATOMIC_REQUESTS': True可以提供数据一致性的保证,但它也可能对性能产生影响。因为每个请求都在其自己的事务中运行,这可能会增加数据库的开销,特别是在高并发的场景中。因此,在决定使用此选项时,应该仔细评估项目的性能和一致性需求。
  • 长时间运行的请求:对于长时间运行的请求(例如,需要处理大量数据的请求),使用'ATOMIC_REQUESTS': True可能会导致事务保持打开状态很长时间,这可能会增加锁定争用和数据库资源的使用。在这种情况下,可能需要考虑其他的事务管理策略。
  • 手动事务管理:即使启用了'ATOMIC_REQUESTS': True,你仍然可以在需要时手动管理事务。Django的数据库API提供了用于开启、提交和回滚事务的函数和上下文管理器。这些工具允许你在需要时覆盖自动事务管理的行为。
  • 未生效: 如果配置全局事务未生效,有可能是数据库不支持如sqlite不支持事务、中间件对异常进行了捕获导致失效、视图函数局部禁用。

    2 开启视图函数的事务

    全局开启事务时,在高并发的请求时,对数据库的压力也挺大的,可以在视图函数中对某些重要的操作开启事务比如支付或订单之类的

    from django.db import transaction
    @transaction.atomic
    def home(request):
        models.Module.objects.create(project_id=1, title="测试事务")
        1/0
        models.IssuesType.objects.create(project_id=1, title="测试事务")
        return render(request, "home.html")
    

    3 手动事务

    我们知道MySQL的写数据时互斥锁,一个视图函数中如果耗时较长,并发请求时事务不及时提交时将会都卡在提交事务上,因此在并发并发高的场景时可以将事务的控制颗粒度设置更细些,手动在关键地方设置事务。

    from django.db import transaction
    def home(request):
        models.Module.objects.create(project_id=1, title="测试事务前")
        with transaction.atomic():
            models.Module.objects.create(project_id=1, title="测试事务")
            1/0
            models.IssuesType.objects.create(project_id=1, title="测试事务")
        return render(request, "home.html")
    

    4 事务保存点

    有时候事务中出现异常,不希望事务中全部的操作都进行回滚,比如记录用户操作行为到数据库的数据我们希望进行回滚

    from django.db import transaction
    def home(request):
        with transaction.atomic():
            models.Module.objects.create(project_id=1, title="操作事务日志记录到数据库")
            try:
                sid = transaction.savepoint()
                models.Module.objects.create(project_id=1, title="测试事务")
                1/0
                models.IssuesType.objects.create(project_id=1, title="测试事务")
            except:
                transaction.savepoint_rollback(sid)  # 回滚到保存点
        transaction.savepoint_commit(sid)
        return render(request, "home.html")
    

    5 开启事务回调

    有时候我们希望事务提交之后做一些额外操作,比如下发订单成功了,立马发送提醒用户。

    from django.db import transaction
    def sen_msg():
        print("事务成功")
    def home(request):
        try:
            with transaction.atomic():
                models.Module.objects.create(project_id=1, title="操作事务日志记录到数据库")
                models.Module.objects.create(project_id=1, title="测试事务")
                # 测试事务是否成功 1 成功执行on_commit 2 失败不执行
                # 1/0
                models.IssuesType.objects.create(project_id=1, title="测试事务")
                transaction.on_commit(sen_msg)
        except Exception:
            print("事务执行失败")
        return render(request, "home.html")