认识常用命令
SHOW ENGINE INNODB STATUS;
介绍
SHOW ENGINE INNODB STATUS; 是 InnoDB 存储引擎提供的一个诊断工具,它会输出一份非常详细的报告,包含 InnoDB 内部多个维度的状态信息。这份报告主要包含以下几个部分:
- BACKGROUND THREAD: 后台主线程(如刷新脏页)的活动信息。SEMAPHORES: 信号量信息,用于诊断线程间争用和锁等待。如果系统存在大量锁等待,这里会有体现。LATEST DETECTED DEADLOCK: 这是你最关心的部分。它记录了最近一次发生的死锁的详细信息,包括:
- TRANSACTIONS: 当前活跃的事务信息。FILE I/O: I/O 相关线程信息。BUFFER POOL AND MEMORY: 缓冲池和内存的使用统计。ROW OPERATIONS: 行操作相关的统计信息。
为什么没查到你的死锁信息?
核心原因:**LATEST DETECTED DEADLOCK** 只记录最近一次死锁。
想象一下,它是一个只能容纳一条记录的“死锁日志表”。当发生一个新的死锁时,旧的记录就会被覆盖。
所以,可能的情况是:
- 在你的程序报错和你在数据库执行
SHOW ENGINE INNODB STATUS; 之间的这段时间内,系统又发生了新的死锁,把你遇到的那个死锁信息给覆盖掉了。数据库可能在你查询之前重启过,因为这份报告是存储在内存中的,重启后会清空。方式汇总
方式一:执行SHOW ENGINE INNODB STATUS;命令
直接执行该命令查看最近的一次死锁日志记录:
SHOW ENGINE INNODB STATUS;
方式二:死锁日志记录
初始化
步骤一:开启并配置永久的死锁日志记录
这是最重要的一步,能让你在死锁发生后从容地分析。
1、开启 InnoDB 死锁日志打印到错误日志:
确保你的 MySQL 配置文件中(如 my.cnf 或 my.ini)有以下配置:
[mysqld] innodb_print_all_deadlocks = ON
这个配置会让 InnoDB 将每一次死锁的详细信息都记录到 MySQL 的错误日志(Error Log)中,而不是仅仅在 SHOW ENGINE INNODB STATUS; 中保留最近一次。
修改后需要重启 MySQL 服务,或者动态设置(需要有权限):
SET GLOBAL innodb_print_all_deadlocks = ON;
2、配置并监控错误日志:
找到你的 MySQL 错误日志文件路径(可以通过 SHOW VARIABLES LIKE 'log_error'; 查看)。
之后,每当发生死锁,你都可以去这个日志文件里搜索 "DEADLOCK" 关键字,找到完整的死锁报告。
步骤二:捕获并分析死锁现场
当你的应用程序(例如,日志中、监控系统)报告死锁错误时(MySQL 通常会返回 Error 1213),立即去检查错误日志。
你会看到类似这样的报告(这是一个简化示例):
*** (1) TRANSACTION: TRANSACTION 123456, ACTIVE 10 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 100, OS thread handle 0x..., query id 1000 ... updating DELETE FROM t1 WHERE a = 1 *** (1) HOLDS THE LOCK(S): -- 事务1持有的锁 RECORD LOCKS space id 100 page no 10 n bits 80 index PRIMARY of table `test`.`t1` trx id 123456 lock_mode X locks rec but not gap Record lock, heap no 5 PHYSICAL RECORD: ... *** (1) WAITING FOR THIS LOCK TO BE GRANTED: -- 事务1在等待的锁 RECORD LOCKS space id 100 page no 11 n bits 80 index sec_idx of table `test`.`t1` trx id 123456 lock_mode X locks rec but not gap waiting Record lock, heap no 6 PHYSICAL RECORD: ... *** (2) TRANSACTION: TRANSACTION 123457, ACTIVE 15 sec starting index read mysql tables in use 1, locked 1 4 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 MySQL thread id 101, OS thread handle 0x..., query id 1001 ... updating DELETE FROM t1 WHERE a = 2 *** (2) HOLDS THE LOCK(S): -- 事务2持有的锁 RECORD LOCKS space id 100 page no 11 n bits 80 index sec_idx of table `test`.`t1` trx id 123457 lock_mode X locks rec but not gap Record lock, heap no 6 PHYSICAL RECORD: ... *** (2) WAITING FOR THIS LOCK TO BE GRANTED: -- 事务2在等待的锁 RECORD LOCKS space id 100 page no 10 n bits 80 index PRIMARY of table `test`.`t1` trx id 123457 lock_mode X locks rec but not gap waiting Record lock, heap no 5 PHYSICAL RECORD: ... *** WE ROLL BACK TRANSACTION (2) -- 数据库选择回滚了事务2
步骤三:解读死锁报告并定位业务代码
分析上面的报告,关键是找到:
涉及的事务:两个(或多个)事务分别在执行什么 SQL?
示例中,两个事务都在执行 DELETE,但条件不同 (a=1 和 a=2)。
- 锁的持有和等待关系:
PRIMARY 索引上某行的 X 锁,正在等待 sec_idx 索引上某行的 X 锁。事务2:持有了 sec_idx 索引上某行的 X 锁,正在等待 PRIMARY 索引上某行的 X 锁。
- 死锁成因:
这就形成了一个典型的“循环等待”:事务1等事务2,事务2又在等事务1。数据库为了打破僵局,选择回滚其中一个(这里是事务2)。
排查过程
1、立即捕获死锁现场
# 1. 立即查询最新死锁信息(趁还没被覆盖) SHOW ENGINE INNODB STATUS\G # 2. 检查死锁记录是否已开启 SHOW VARIABLES LIKE 'innodb_print_all_deadlocks'; # 3. 如果未开启,立即开启(避免后续死锁丢失) SET GLOBAL innodb_print_all_deadlocks = ON;
2、定位日志中的死锁情况
# 1. 找到错误日志位置 mysql -e "SHOW VARIABLES LIKE 'log_error';" # 2. 实时监控错误日志中的死锁(推荐) tail -f /var/log/mysql/error.log | grep -A 50 -B 5 "DEADLOCK" # 3. 或者搜索历史死锁记录 grep -A 50 "DEADLOCK" /var/log/mysql/error.log
3、快速分析核心问题
在死锁日志中,重点关注以下4个部分: text LATEST DETECTED DEADLOCK ------------------------ *** (1) TRANSACTION: [关键点1:事务1信息] TRANSACTION 1234, ACTIVE 10 sec updating mysql tables in use 1, locked 1 [看这里→] UPDATE table_x SET ... WHERE id = 1 [关键SQL1] *** (1) HOLDS THE LOCK(S): [关键点2:事务1持有的锁] RECORD LOCKS index `idx_name` of table `db`.`table` trx id 1234 lock_mode X *** (1) WAITING FOR THIS LOCK(S): [关键点3:事务1等待的锁] RECORD LOCKS index `primary` of table `db`.`table` trx id 1234 lock_mode X waiting *** (2) TRANSACTION: [关键点4:事务2信息] TRANSACTION 1235, ACTIVE 8 sec updating [看这里→] UPDATE table_x SET ... WHERE id = 2 [关键SQL2]
4、快速诊断模板
对照这个模板分析:
紧急应对策略:
-- 1. 查看当前锁等待情况(辅助分析) SELECT * FROM information_schema.INNODB_LOCKS; SELECT * FROM information_schema.INNODB_LOCK_WAITS; -- 2. 查看当前活跃事务 SELECT * FROM information_schema.INNODB_TRX ORDER BY trx_started DESC;
死锁解决方案
1、分析是否事务过大导致。
2、有无涉及到两段代码为:
A B
B A
的过程
相关排查思路文章
[1]. Mysql死锁日志分析:事务逻辑冲突的排查技巧
[2]. MySQL 故障案例分析:从死锁到数据丢失的全面诊断指南
到此这篇关于MySQL死锁类deadlock问题排查的文章就介绍到这了,
