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

如何处理异步POST场景的django.db.utils.IntegrityError?可否捕获该错误?

问题根因

你遇到的是典型的应用层查重竞态问题:BEFORE_CREATE钩子内的slug存在性校验是在Django应用层执行的,并发请求下两个事务会同时完成查重判断,都认为["hello"]不存在,随后同时写入触发唯一约束冲突。
另外你原代码里还有两个语法问题可以顺便修正:一是populate_slug方法内的slug变量没有初始化,二是拼接后缀的语法错误f"{slug[0]-{n}"应为f"{slug[0]}-{n}"。

方案1:捕获IntegrityError重试(推荐,符合你的需求)

不需要把钩子改成AFTER_CREATE,只要在创建逻辑的外层加冲突捕获重试即可,只有出现冲突的时候才会重试写入,正常场景下不会产生额外的数据库操作,你可以把这个逻辑封装为独立的创建方法,或者放在视图层:

from django.db import IntegrityError, transaction
from django.utils.text import slugify

def create_item(title: str) -> Item:
    base_slug = slugify(title)
    # 加重试上限避免极端场景下无限循环
    max_retry = 100
    retry_count = 0
    while retry_count < max_retry:
        try:
            # 原子事务保证创建失败时回滚脏数据
            with transaction.atomic():
                if retry_count == 0:
                    current_slug = [base_slug]
                else:
                    current_slug = [f"{base_slug}-{retry_count + 1}"]
                return Item.objects.create(title=title, slug=current_slug)
        except IntegrityError as e:
            # 只捕获slug唯一约束冲突的错误,其他错误正常抛出
            if "app_item_slug_key" not in str(e):
                raise
            retry_count += 1
    raise RuntimeError("slug生成重试次数超限")

后续创建Item时直接调用create_item方法即可,无需再依赖原来的BEFORE_CREATE钩子,也可以把这段逻辑整合到钩子内部。

其他可选方案

  • 如果你并发量极高,可以把slug生成逻辑放到PostgreSQL的触发器中实现,完全在数据库层面保证操作的原子性,缺点是业务逻辑散落在数据库中,维护成本更高。
  • 也可以使用PostgreSQL的咨询锁(Advisory Lock)在创建前加全局锁,避免并发冲突,但锁的粒度更粗,高并发下性能会受影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:54:03