Django中uniqueConstraint与get_or_create并发失效问题求助
问题原因
select_for_update的局限性:select_for_update仅能锁定已存在的数据库行,当并发请求进来时,所有请求的get操作都找不到目标草稿,此时无法加锁,所有请求都会进入create分支,同时尝试插入数据触发唯一约束冲突。- 事务隔离级别影响:默认的
读已提交隔离级别下,事务只能看到其他事务已提交的修改。第一个请求创建草稿后未提交时,其他并发请求仍看不到这条记录,会继续执行创建操作。 - 冗余的
save()调用:get_or_create在创建记录时会自动执行保存,额外调用save()属于冗余操作,无实际作用。
解决方案
方案1:锁定用户行(推荐)
通过锁定当前用户的数据库行,确保同一时间只有一个请求能处理该用户的草稿创建,从根源避免竞态:
from django.db import transaction @transaction.atomic def create_new_request(self, request: Request): # 先锁定当前用户行,同一用户的并发请求会排队等待锁释放 user = User.objects.select_for_update().get(id=request.user.id) # 执行get_or_create,此时不会有并发冲突 purchase_request, request_created = PurchaseRequest.objects.get_or_create( requester=user, status="draft", ) print("get or created: ", purchase_request.id, request_created)
方案2:捕获唯一约束异常并重试
利用数据库的唯一约束作为最终校验,捕获IntegrityError后重新查询已创建的记录,属于乐观锁思路:
from django.db import transaction, IntegrityError def create_new_request(self, request: Request): while True: try: with transaction.atomic(): purchase_request, request_created = PurchaseRequest.objects.get_or_create( requester=request.user, status="draft", ) break except IntegrityError: # 冲突说明其他请求已创建记录,直接查询即可 purchase_request = PurchaseRequest.objects.get( requester=request.user, status="draft", ) request_created = False break print("get or created: ", purchase_request.id, request_created)
方案3:精细行锁+异常处理
先尝试锁定已存在的草稿,不存在则创建,同时处理并发创建的冲突:
from django.db import transaction, IntegrityError @transaction.atomic def create_new_request(self, request: Request): request_created = False try: # 尝试获取并锁定已存在的草稿 purchase_request = PurchaseRequest.objects.select_for_update().get( requester=request.user, status="draft", ) except PurchaseRequest.DoesNotExist: try: # 不存在则创建 purchase_request = PurchaseRequest.objects.create( requester=request.user, status="draft", ) request_created = True except IntegrityError: # 并发创建冲突,重新查询已存在的记录 purchase_request = PurchaseRequest.objects.get( requester=request.user, status="draft", ) print("get or created: ", purchase_request.id, request_created)
内容的提问来源于stack exchange,提问作者paul23
相关产品推荐
相关产品推荐

