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

不使用自增列时MySQL并发插入唯一ID重复解决方案

问题原因

你写的代码里\DB::raw('LOCK TABLES leads WRITE')和\DB::raw('UNLOCK TABLES')根本没有实际执行。Laravel的DB::raw()方法仅用于生成原生SQL表达式片段,不会向数据库发送请求执行SQL,等于加锁、解锁逻辑完全没生效。
默认数据库事务隔离级别下,多个并发请求会同时查到同一个max(id)值,最终插入重复id。另外MySQL的LOCK TABLES语句本身会隐式提交当前活跃事务,你代码里先开事务再执行锁表的顺序本身也是错的,就算真的执行了锁表SQL也会破坏事务逻辑。

解决方案

方案1:修正表锁逻辑(改动最小)

调整锁表语句的执行方式和顺序,不要用DB::raw()跑锁表SQL,改用DB::statement()实际执行SQL,同时调整锁和事务的顺序:

<?php
for($i=1; $i<1000; $i++){
    // 先执行写锁,阻塞其他会话对leads表的读写
    \DB::statement('LOCK TABLES leads WRITE');
    
    $max = (int)\DB::table('leads')->max('id');
    $newId = str_pad(++$max, 10, '0', STR_PAD_RIGHT);
    \DB::table('leads')->insert(['id' => $newId]);
    
    // 操作完成后解锁,自动释放锁给其他排队请求
    \DB::statement('UNLOCK TABLES');
}

这个方案改动最小,但是写锁会锁整张leads表,并发高的时候吞吐量会比较低。

方案2:用序列表+行级悲观锁(性能更好)

单独建一张只存id序列值的小表,用行级锁代替表锁,并发性能高很多:

  1. 先建序列表,初始化一条记录存当前最大id:
    CREATE TABLE leads_seq (
        current_max_id INT UNSIGNED NOT NULL DEFAULT 0
    );
    INSERT INTO leads_seq (current_max_id) SELECT IFNULL(MAX(id),0) FROM leads;
    
  2. 业务代码里用lockForUpdate()加行级排他锁,保证同一时间只有一个请求能读取、修改序列值:
    <?php
    for($i=1; $i<1000; $i++){
        \DB::beginTransaction();
        // 排他锁锁定序列记录,其他请求会在这里阻塞等待锁释放
        $seq = \DB::table('leads_seq')->lockForUpdate()->first();
        $newIdValue = $seq->current_max_id + 1;
        // 更新序列值
        \DB::table('leads_seq')->update(['current_max_id' => $newIdValue]);
        // 插入业务表
        \DB::table('leads')->insert([
            'id' => str_pad($newIdValue, 10, '0', STR_PAD_RIGHT)
        ]);
        \DB::commit();
    }
    

这个方案锁的粒度是序列表的单行记录,不会阻塞leads表的其他查询操作,并发表现远好于锁全表。

兜底必做项

不管用上面哪种方案,都要给leads表的id字段加唯一索引,从数据库层面彻底挡住重复id写入,就算代码逻辑出极端异常,也不会出现重复id的脏数据。如果插入时触发唯一索引冲突,捕获异常后重试1-2次即可。

注意:Laravel中所有需要实际执行的原生SQL,都不能直接靠DB::raw()触发,必须调用statement()/select()/insert()/update()这类会实际发起数据库连接请求的方法,DB::raw()本身只负责拼接SQL片段,不会执行任何数据库操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:45:36