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
相关产品推荐
相关产品推荐

