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

Django中uniqueConstraint与get_or_create并发失效问题求助

问题原因

  1. select_for_update的局限性:select_for_update仅能锁定已存在的数据库行,当并发请求进来时,所有请求的get操作都找不到目标草稿,此时无法加锁,所有请求都会进入create分支,同时尝试插入数据触发唯一约束冲突。
  2. 事务隔离级别影响:默认的读已提交隔离级别下,事务只能看到其他事务已提交的修改。第一个请求创建草稿后未提交时,其他并发请求仍看不到这条记录,会继续执行创建操作。
  3. 冗余的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:12:06