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

Django中transaction.atomic下死锁及重复条目报错问题咨询

解决并发更新/创建时的重复记录、唯一约束报错与死锁问题

兄弟,你遇到的是并发场景下典型的竞态条件问题——两次请求同时执行get都没找到记录,接着同时触发create,这时候唯一约束就会抛出重复条目错误,极端情况下还会因为数据库锁的竞争引发死锁。下面给你几个靠谱的解决方案:

1. 用ORM原生的原子操作(最推荐)

Django的update_or_create方法是数据库层面原子执行的,底层会根据数据库类型自动生成INSERT ... ON DUPLICATE KEY UPDATE(MySQL)或者类似的原子语句,从根源避免竞态。

替换你原来的try-except代码:

obj, created = model.objects.update_or_create(
    # 这里放你的唯一约束字段(对应x_y_z_uniq的字段)
    id=id,
    user=y,
    # 需要更新的字段放在defaults里
    defaults={'completed': True}
)
  • 这个方法会自动判断:如果记录存在就更新completed为True,不存在就创建新条目
  • 全程是原子操作,并发请求不会同时进入创建流程,也就不会出现重复记录或死锁

2. 手动加事务+行级锁(适合自定义逻辑场景)

如果你需要更精细的控制,可以用select_for_update结合事务,手动锁定行避免竞态:

from django.db import transaction

with transaction.atomic():
    try:
        # select_for_update会锁定查询到的行,防止其他请求修改
        obj = model.objects.select_for_update().get(id=id, user=y)
        obj.completed = True
        obj.save()
    except model.DoesNotExist:
        model.objects.create(id=id, user=y, completed=True)
  • 事务保证整个操作的原子性,select_for_update避免并发请求同时修改同一记录
  • 即使极端情况下有并发创建,唯一约束会拦截,但因为事务的存在,不会引发死锁

3. 加重试机制处理极端并发

如果偶尔还是会遇到IntegrityError(比如超高频并发),可以给操作加个重试逻辑:

from django.db import IntegrityError
import time

max_retries = 3
retry_delay = 0.1

for _ in range(max_retries):
    try:
        obj, created = model.objects.update_or_create(
            id=id,
            user=y,
            defaults={'completed': True}
        )
        break
    except IntegrityError:
        time.sleep(retry_delay)
        retry_delay *= 2  # 指数退避,减少冲突概率
else:
    # 重试多次失败,根据业务需求处理(比如抛异常或记录日志)
    raise RuntimeError("Failed to update/create record after multiple retries")

4. 数据库层面的优化

  • 确保你的唯一约束索引x_y_z_uniq是组合索引(包含id、user等相关字段),这样数据库能快速判断重复,减少锁竞争时间
  • 如果你用的是MySQL,确保表用的是InnoDB引擎(默认就是),它的行级锁比MyISAM的表锁更适合并发场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:01:15