You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中执行多次save操作的正确方法,如何规避竞态条件?

Django 多save操作的正确性与事务处理方案

原代码的问题

你给出的代码在功能上可以正常执行,但存在两个明显缺陷:

  • 不保证原子性:三个save操作没有事务包裹,只要其中任意一个执行失败(比如数据库连接中断、字段校验不通过),已经执行成功的save操作的修改会永久保留在数据库中,造成数据不一致。比如前两个save成功、第三个save失败时,会出现process已绑定用户、用户已标记为更新,但对应操作记录缺失的问题,不符合业务逻辑的完整性要求。
  • 存在竞态条件隐患:如果多个请求同时操作同一个user或process对象,先查后改的save逻辑会出现更新覆盖的问题,比如两个请求同时修改同一个用户的is_updated字段,后提交的修改会覆盖前一个的操作结果。

是否需要使用@transaction.atomic

非常需要。这个场景完全符合事务的使用条件,@transaction.atomic会把包裹范围内的所有数据库操作绑定为一个原子单元,要么全部执行成功,要么全部回滚,从根本上避免部分操作成功的脏数据问题。

更合理的实现方式

1. 基础事务包裹(满足大多数场景)

直接给对应的视图函数加上@transaction.atomic装饰器即可:

from django.db import transaction

@transaction.atomic
def your_view(request):
    # 其他前置业务逻辑
    process.user = user
    process.save()

    user.is_updated = True
    user.save()

    actions = Actions(owner=user, action="Personal")
    actions.save()

2. 解决竞态条件的优化方案

如果你的业务场景存在高并发修改同一行数据的可能,可以通过以下两种方式规避竞态问题:

  • 查询对象时加行锁:查询user和process对象时使用select_for_update()方法,在事务生效期间锁定对应的数据库行,其他事务无法修改锁定的行,避免更新覆盖:
    # 查询阶段就加锁
    user = User.objects.select_for_update().get(id=user_id)
    process = Process.objects.select_for_update().get(id=process_id)
    
  • 原子更新单个字段:如果只需要修改user的is_updated字段,不需要先查询再保存,直接调用update方法执行原子修改,本身不会有竞态问题:
    User.objects.filter(id=user.id).update(is_updated=True)
    

内容的提问来源于stack exchange,提问作者sixovov947

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:15:08