You need to enable JavaScript to run this app. 如何在PHP构建的RestAPI中避免重复请求引发的订单号重复问题
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP构建的RestAPI中避免重复请求引发的订单号重复问题

纯PHP侧解决订单重复、接口限流的实现思路

核心问题本质

你遇到的毫秒级并发下的重复问题,根源是所有“先查询状态、再执行业务、最后写入状态标记”的逻辑都是非原子的:多PHP进程的内存相互隔离,哪怕你在第一个请求里刚写入“这个IP已经请求过了”的标记,其他同时发起的并行请求在同一时间节点的查询操作,根本读不到还没提交完成的写入结果,最终所有进程都判定“没有同类请求”,直接往下执行业务,生成重复订单。
所有没有依托操作系统/存储层原子操作实现的校验逻辑,在数毫秒间隔的并发下完全失效。

订单号生成的无重复实现

要在纯PHP层杜绝重复order_number,不能依赖普通的查询自增逻辑,必须用跨进程生效的原子互斥锁:

  • 优先使用PHP原生文件锁实现,不需要额外中间件依赖:通过flock()函数的内核级原子锁机制,保证同一时间只有一个进程能进入订单生成的临界区
    参考实现代码:
    function place_order($data) {
        // 打开固定的锁文件,c模式代表文件不存在就创建,存在就打开
        $lockFp = fopen('/tmp/order_create_global.lock', 'c');
        // 非阻塞获取独占锁:LOCK_EX=独占锁,LOCK_NB=不等待锁占用,拿不到就立刻返回
        if (!flock($lockFp, LOCK_EX | LOCK_NB)) {
            http_response_code(429);
            exit('当前请求繁忙,请稍后重试');
        }
        // 拿到锁的进程进入临界区,完整执行订单生成逻辑
        $order_number = $db->getOne('SELECT MAX(order_number) FROM orders');
        $order_number++;
        try {
            $db->query('INSERT INTO orders(order_number, data) VALUES(?,?)', 
                [$order_number, $data]);
        } finally {
            // 无论执行成功还是抛错,都主动释放锁
            flock($lockFp, LOCK_UN);
            fclose($lockFp);
        }
    }
    
  • 如果服务部署了Redis,也可以用Redis的原子指令实现锁:用SET 锁key 随机值 NX EX 过期时间,其中NX语义是只有key不存在的时候才会设置成功,是原子操作,跨进程生效,不会出现多个进程同时拿锁的问题
    注意:必须直接用带NX参数的SET指令,不能拆成“先查key是否存在、不存在再设置”两步,否则和最初的订单号自增逻辑有一样的竞态问题

同IP短时间重复请求拦截

同样基于原子锁的逻辑实现限流,完全可以覆盖毫秒级的并行请求场景:

  • 针对每个客户端IP生成对应的锁key,比如ip_limit_123.123.123.123
  • 尝试用和上面一致的原子操作(文件锁/Redis原子锁)获取这个IP对应的锁,锁的过期时间直接设置为你需要的限流窗口(比如3秒)
  • 第一个发起请求的进程会成功拿到锁,后续同IP的所有并行请求在同一毫秒发起时,会立刻检测到锁已被占用,直接返回请求频繁的提示,根本不需要走到业务逻辑层
  • 这个逻辑的响应延迟是微秒级的,完全不会被毫秒级的并行请求穿透

兜底机制

哪怕PHP层的锁逻辑做的再完善,也一定要给数据库的order_number字段加UNIQUE唯一索引:

  • 这是最后一道防线,比如遇到进程崩溃没来得及释放锁、极端场景锁失效的情况,数据库的唯一约束会直接拦截重复值的写入,不会产生脏数据
  • 配合这个约束,PHP层在收到数据库抛出的重复键报错时,可以自动重试一次订单创建流程,不需要人工介入修复

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 22:27:04