innodb在行锁等待时主动将事务加入锁等待队列,构建等待图实时检测环形依赖,一旦发现死锁即回滚代价最小的事务;普通select走mvcc快照读不加锁,而select...for update需加x锁参与竞争;innodb_lock_wait_timeout仅控制等锁超时,非sql执行超时。

行锁等待时,InnoDB到底在做什么?
不是“卡住了”,而是事务明确进入了锁等待状态——InnoDB已为当前SQL定位到目标索引记录,并发现该记录已被其他事务加了不兼容的锁(比如你执行 UPDATE 要加 X 锁,但别人正拿着 S 锁或 X 锁没释放),于是主动挂起当前线程,把它塞进对应锁对象的等待队列里。
关键点在于:这个等待是**主动注册、可检测、有超时**的,不是操作系统级阻塞。InnoDB 用一个哈希表(Lock Table)快速映射“哪把锁被谁持有、谁在等”,再用等待图(Wait-for Graph)实时扫描是否存在循环依赖——一旦发现 A 等 B、B 等 C、C 又等 A,立刻触发死锁检测,回滚其中一个事务。
为什么SELECT ... FOR UPDATE会等,而普通SELECT不会?
因为普通 SELECT 默认走 MVCC 快照读,不加任何锁;而 SELECT ... FOR UPDATE 是当前读,必须看到最新版本并加 X 锁,所以要参与锁竞争。
- 如果 WHERE 条件命中唯一索引且记录存在 → 尝试对那条索引记录加 X 锁,冲突就等
- 如果 WHERE 条件是范围查询(如
id > 100)→ 可能要加 next-key lock,锁住整个区间,等待范围可能远大于你肉眼看到的几行 - 如果条件字段没索引 → 全表扫描,每扫一条就尝试加锁,实际等的是“第一条冲突记录”,但日志里常显示
Waiting for table metadata lock或长时间无响应,本质是锁队列积压
innodb_lock_wait_timeout 控制什么?它真能帮你“及时脱身”吗?
它只控制“等锁超时”,不是“SQL执行超时”。也就是说,只要还没等到锁,计时器就在跑;一旦拿到锁开始执行 UPDATE,哪怕后面花 10 秒更新 10 万行,这个参数也不起作用。
默认值是 50 秒,但线上业务通常设为 5~10 秒。注意两个坑:
- 超时抛出的错误是
Lock wait timeout exceeded; try restarting transaction,不是死锁,应用层需捕获并重试 - 它对持有锁的事务毫无影响——对方可能还在慢查询、没提交、甚至连接已断但事务未回滚,你的等待只会白费
- 调小它能减少堆积,但不能降低死锁率;真正要改的是 SQL 是否走索引、事务是否过长、隔离级别是否必要用 RR
从 SHOW ENGINE INNODB STATUS 里看等待,最该盯哪几行?
别只扫一眼“LATEST DETECTED DEADLOCK”,日常排查锁等待,重点看 “TRANSACTIONS” 部分里每个事务的 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: 和 *** (2) HOLDS THE LOCK(S): 这两块。
示例片段:
---TRANSACTION 123456789, ACTIVE 12 sec mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s) *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 123 page no 456 n bits 72 index `idx_phone` of table `db`.`users` trx id 123456789 lock_mode X locks rec but not gap waiting *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 123 page no 456 n bits 72 index `idx_phone` of table `db`.`users` trx id 123456788 lock_mode X locks rec but not gap
这里你能直接看出:trx id 123456789 在等 idx_phone 上某条记录的 X 锁,而 trx id 123456788 正拿着它——顺着这个 trx id 去查它的 SQL、运行时长、是否 COMMIT/ROLLBACK,才是根因。
真正容易被忽略的是:锁等待本身不产生慢日志,除非超时;而持有锁的事务如果执行慢、不提交,它就像一根刺扎在那里,所有后续请求都得排队等——问题不在等的人,而在不放手的人。











