
show engine innodb status;当业务系统报错 Deadlock found when trying to get lock 时,必须第一时间登录 MySQL 客户端执行命令提取日志。
执行命令:
SHOW ENGINE INNODB STATUS\G查看位置:
在输出的庞大文本中,直接向下滚动或搜索关键字,定位到 ------------------------ LATEST DETECTED DEADLOCK ------------------------ 这一段。此部分记录了系统检测到的最近一次死锁的完整上下文。
在死锁日志中,InnoDB 会将冲突的事务标记为 (1) TRANSACTION 和 (2) TRANSACTION。需要从中提取正在执行的 SQL 语句。
提取过程:
在日志的 (1) TRANSACTION 块中,寻找 query id 字段:
*** (1) TRANSACTION:
TRANSACTION 4561, ACTIVE 10 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 12, OS thread handle 1407, query id 100 update t set c = c + 1 where id = 2结论 1: 事务 1 发生死锁时正在执行的 SQL 是 update t set c = c + 1 where id = 2。
在 (2) TRANSACTION 块中,进行同样的寻找:
*** (2) TRANSACTION:
TRANSACTION 4562, ACTIVE 8 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 13, OS thread handle 1408, query id 105 update t set c = c + 1 where id = 1结论 2: 事务 2 发生死锁时正在执行的 SQL 是 update t set c = c + 1 where id = 1。
找到 SQL 后,必须结合日志中 HOLDS THE LOCK(S)(当前持有的锁)和 WAITING FOR THIS LOCK TO BE GRANTED(正在等待的锁)部分,明确锁的类型和级别。
分析事务 1 的日志细节:
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 50 page no 4 n bits 72 index PRIMARY of table `test`.`t` trx id 4561 lock_mode X locks rec but not gap waitingindex PRIMARY:说明锁加在主键索引上。lock_mode X:申请的是排他锁(X锁)。locks rec but not gap:这是一个纯粹的记录锁(Record Lock),不包含间隙锁。waiting:表示该锁正在排队等待获取。分析事务 2 的日志细节:
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 50 page no 4 n bits 72 index PRIMARY of table `test`.`t` trx id 4562 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 50 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 4562 lock_mode X locks rec but not gap waitingHOLDS THE LOCK(S) 明确指出,事务 2 已经持有了某一行的排他记录锁(对应 id=2 的行)。WAITING FOR 指出,事务 2 正在申请另一行的排他记录锁(对应 id=1 的行)。根据上述 SQL 和加锁分析结果,可以完全反向推导出应用程序在死锁发生前的执行时序。假设表 t 的结构包含主键 id。
时间轴还原:
时间节点 | 事务 1 (Session A) | 事务 2 (Session B) | 状态变化 |
|---|---|---|---|
T1 |
|
| 开启事务 |
T2 |
| 成功。事务 1 获取 | |
T3 |
| 成功。事务 2 获取 | |
T4 |
| 阻塞。请求 | |
T5 |
| 触发死锁。请求 |
将模拟现场与日志进行逻辑闭环验证。
id=2 的锁,与模拟中 T4 节点完全吻合。id=2 的锁,等待 id=1 的锁,与模拟中 T3 和 T5 节点完全吻合。innodb_deadlock_detect=ON)扫描到了锁等待图(Wait-for Graph)中存在有向环。在日志的最后一行,会记录系统的处理决定:
*** WE ROLL BACK TRANSACTION (2)结果剖析:
id=2 的锁,从而让事务 1 能够获取锁并继续执行。trx_weight)。该权重取决于事务修改的行数和占用的锁数量。在此次案发中,系统判定事务 2 的回滚成本低于事务 1。UPDATE 涉及的 id 进行强制升序排序,确保所有事务均按照 id=1 -> id=2 的顺序加锁,即可从物理上切断循环等待链,彻底避免该死锁。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。