mysql死锁排查需先看show engine innodb status日志定位冲突事务、持有/等待锁及sql,再查innodb_trx和data_locks确认锁状态,最后依索引类型、隔离级别、是否走索引反推加锁规则,并通过统一加锁顺序、拆分事务、设超时等预防。

MySQL死锁排查在面试中常以“现场分析+逻辑推演”形式出现,重点不是背结论,而是展现你对加锁机制、事务行为和日志工具的理解路径。以下四个高频实战案例,覆盖典型场景和关键排查动作。
看日志定位死锁事务和SQL
线上报错通常直接给出关键线索:
- 错误信息:“Deadlock found when trying to get lock; try restarting transaction”——说明InnoDB已检测到死锁并主动回滚了其中一个事务
-
死锁日志(可通过
SHOW ENGINE INNODB STATUS\G获取)会明确列出两个冲突事务的:
– 事务ID、运行时间、持有的锁(如X锁 on PRIMARY index, gap lock on (20,30))
– 等待的锁(如waiting for X lock on PRIMARY index, insert intention lock in gap (20,30))
– 最后执行的SQL语句 - 注意:日志中“LATEST DETECTED DEADLOCK”区块只保留最近一次死锁详情,需及时捕获
查锁状态确认资源争用点
仅靠日志不够细?进一步验证当前锁分布:
- 查活跃事务:
SELECT * FROM information_schema.INNODB_TRX;关注trx_state(RUNNING / LOCK WAIT)、trx_started、trx_query - 查具体锁:
SELECT * FROM performance_schema.data_locks WHERE LOCK_TRX_ID IN (SELECT trx_id FROM information_schema.INNODB_TRX);
重点关注LOCK_MODE(X,GAP / X,REC_NOT_GAP / X / IX)、LOCK_TYPE(RECORD / TABLE)、INDEX_NAME和LOCK_DATA(锁定的具体值或间隙) - 例如看到两个事务都在
PRIMARY索引上对(20,30)加了X,GAP锁,又都试图插入id=25,就基本能复现死锁链
按加锁规则反推为什么锁住这里
面试官常追问:“这条UPDATE为什么加的是间隙锁而不是行锁?”答案取决于三个前提:
- 索引类型:主键/唯一索引等值查询且命中 → 加记录锁(X, REC_NOT_GAP);未命中 → 加间隙锁(X, GAP)
- 隔离级别:RR下默认用next-key lock(行锁+前隙锁),RC下无间隙锁,死锁概率显著降低
- 查询条件是否走索引:没走索引 → 全表扫描 → 每行都加X锁 → 锁范围爆炸,极易引发死锁
- 经典例子:
UPDATE t_student SET score=100 WHERE id=25;若id=25不存在,RR下会在(20,30)加间隙锁;若同时有INSERT id=25,则需插入意向锁,与间隙锁冲突
从代码和设计层面避免重蹈覆辙
排查是救火,预防才是关键。面试时给出可落地的改进点更显深度:
-
统一加锁顺序:多个ID更新时,强制按主键升序排列再
SELECT ... FOR UPDATE,避免A锁(1,3)、B锁(3,1)的交叉 - 减少事务粒度:把长事务拆成短事务,尤其避免在事务内做RPC调用、文件读写等耗时操作
-
合理设超时:
innodb_lock_wait_timeout调低(如5秒),让等待方快速失败,而非卡死 -
业务兜底:对“查无则插”类操作,优先用
INSERT ... ON DUPLICATE KEY UPDATE,避免先查后更的两阶段锁










