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

Django事务中执行批量更新代码是否仍存在竞态条件?

Django事务中的竞态条件问题解答

你的理解完全正确——这段代码确实存在竞态条件,事务没法解决这个问题。

原因分析

transaction.atomic()仅保证代码块内的操作是原子性的(要么全部执行成功,要么全部回滚),但它不会为读取操作自动锁定行。当多个线程/进程同时执行这段代码时:

  1. 所有线程都会先读取到Item表中相同的count初始值
  2. 各自在内存中将count加1
  3. 最后执行bulk_update写入数据库
    最终的结果就是,多个线程基于同一个旧值更新,导致count的增量远小于实际执行的次数(比如两个线程同时处理count=5,最终结果会是6而不是预期的7)。

解决办法

1. 使用行级锁(select_for_update)

在读取时就锁定目标行,阻止其他事务读取旧数据:

with transaction.atomic():
    # 读取时加行级锁,其他事务需等待当前事务提交才能读取
    items = Item.objects.select_for_update().all()
    for item in items:
        item.count += 1
    Item.objects.bulk_update(items, ['count'])

2. 数据库原子更新(推荐)

直接让数据库完成增量操作,跳过先读后写的步骤,从根源避免竞态:

from django.db.models import F

# 数据库层面直接对所有Item的count加1,原子性执行
Item.objects.update(count=F('count') + 1)

这种方式效率更高,不需要循环和批量更新,所有操作由数据库原子完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:42:04