一、死锁日志的关键解析点
-
事务锁持有与等待关系
- 定位日志中
WAITING FOR THIS LOCK(等待锁)和HOLDS THE LOCK(持有锁)字段,明确事务互相阻塞的锁资源。 - 示例:事务A持有行R1锁并等待R2,事务B持有R2锁并等待R1,形成循环等待。
- 定位日志中
-
锁类型与范围识别
- 分析锁类型:行锁(
RECORD LOCKS)、间隙锁(GAP)或临键锁(Next-Key Lock)。 - 检查锁范围:确认锁定的索引、行记录或间隙区间(如
space id 123 page no 3)。
- 分析锁类型:行锁(
-
触发SQL与执行顺序
- 从日志提取引发死锁的具体SQL语句(如
UPDATE accounts SET balance=... WHERE id=?)。 - 结合事务启动时序,还原冲突操作序列(如交叉更新、顺序不一致)。
- 从日志提取引发死锁的具体SQL语句(如
二、事务逻辑冲突的排查方法
-
循环等待验证
- 检查是否存在“事务A锁资源X → 等待Y;事务B锁Y → 等待X”的环路。
- 典型场景:交叉更新两张表(如先更订单再更库存 vs 先更库存再更订单)。
-
并发操作顺序分析
- 对比多事务对相同资源的操作顺序是否一致(如全局约定“先更新表A后更新表B”)。
- 排查长事务未提交导致锁持有时间过长。
-
索引与锁冲突关联
- 无索引或低效索引引发全表锁,扩大锁竞争范围。
- 辅助索引未覆盖更新字段时,同时锁定主键索引与辅助索引6(案例:更新
status字段触发冗余辅助索引锁)。
-
隔离级别的影响
REPEATABLE READ下间隙锁易引发死锁(如范围查询后插入冲突)。- 对比
READ COMMITTED是否降低锁冲突概率。
三、解决方案与预防措施
| 措施 | 操作说明 |
|---|---|
| 统一资源访问顺序 | 约定所有事务按相同顺序操作资源(如固定先更表A再更表B) |
| 精简事务与锁范围 | 避免长事务;更新前精确限定条件(利用索引缩小锁定行) |
| 索引优化 | 移除低区分度索引字段(如状态列);确保更新字段被索引覆盖 |
| 锁升级策略 | 改用乐观锁(版本号控制)或悲观锁(SELECT FOR UPDATE提前占锁) |
| 应急处理 | 通过SHOW ENGINE INNODB STATUS定位死锁后,用KILL [trx_id]终止阻塞事务 |
四、诊断辅助命令速查
sql
-- 1. 实时死锁日志 SHOW ENGINE INNODB STATUS; -- 提取LATEST DETECTED DEADLOCK区块:ml-citation{ref="9,11" data="citationList"} -- 2. 活跃事务与锁信息 SELECT * FROM information_schema.INNODB_TRX; -- 查看未提交事务:ml-citation{ref="9" data="citationList"} SELECT * FROM information_schema.INNODB_LOCKS; -- 当前持有锁:ml-citation{ref="9" data="citationList"} SELECT * FROM information_schema.INNODB_LOCK_WAITS; -- 锁等待链:ml-citation{ref="9,22" data="citationList"} -- 3. 进程与表锁状态 SHOW PROCESSLIST; -- 定位阻塞源头:ml-citation{ref="21,24" data="citationList"} SHOW OPEN TABLES WHERE In_use > 0; -- 检查表级锁争用:ml-citation{ref="9,21" data="citationList"}
关键提示:开启
innodb_print_all_deadlocks=ON记录完整死锁日志;业务代码审查重点为交叉更新、事务隔离级别选择及索引合理性。