MySQL大规模批量插入不建议显式加锁,因InnoDB已自动加隐式锁;显式锁会扩大锁粒度、引发死锁或串行化;应通过BEGIN/COMMIT分批控制事务边界,并确保INSERT走主键或唯一索引以避免间隙锁。

MySQL在大规模批量插入时**不建议显式加锁**——这是个常见误解。真正需要的是控制隐式锁行为,而不是主动加SELECT ... FOR UPDATE或LOCK TABLES这类显式锁。
为什么显式加锁反而会加剧死锁和阻塞
批量插入本身已由InnoDB自动加隐式锁(如插入意向锁、间隙锁),若再叠加显式锁:
-
SELECT ... FOR UPDATE会提前锁定范围,扩大锁粒度,与后续INSERT的插入意向锁冲突 - 表级显式锁(如
LOCK TABLES t WRITE)直接让整张表串行化,吞吐归零 - 多个线程各自执行
SELECT ... FOR UPDATE + INSERT,极易因加锁顺序不一致触发死锁
真正该“显式控制”的是事务边界和锁范围
所谓“建议显式”,实指用可控方式管理InnoDB的隐式锁机制,核心是两点:
- 用
BEGIN/COMMIT明确划分小事务,避免长事务拖住锁(例如每1000条COMMIT一次) - 确保
INSERT走索引:主键或唯一索引能触发精确的Record Lock;否则退化为Next-Key Lock,锁住整个间隙 - 避免
INSERT INTO SELECT无WHERE条件或缺失索引,防止全表扫描+全表加锁
什么时候才真要显式锁?极少数例外场景
仅当业务逻辑强制要求“读-判-插”原子性,且无法用唯一约束替代时才考虑:
- 检查某值不存在后再插入(防重复),但又不能依赖
INSERT IGNORE或ON DUPLICATE KEY UPDATE - 必须基于当前最新状态做决策(如库存扣减前查余额),此时用
SELECT ... FOR UPDATE加锁是合理的,但应配合WHERE精确条件,且事务尽可能短 - 注意:
SELECT ... FOR UPDATE在REPEATABLE READ下会锁住间隙,若条件不命中任何记录,仍可能锁住空隙,引发幻读阻塞
最常被忽略的一点:批量插入性能瓶颈往往不在锁本身,而在事务日志刷盘(innodb_flush_log_at_trx_commit=1)和唯一索引维护开销。调优优先级应是分批提交 → 关闭自动提交 → 调整日志刷盘策略 → 最后才碰锁逻辑。


















