MySQL事务死锁排查方法总结
·
MySQL事务死锁排查的常用方法如下(以5.7版本为例):
一、检查死锁日志
1. 开启死锁日志记录
-- 查看当前设置
SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';
SHOW VARIABLES LIKE 'innodb_status_output_locks';
-- 开启详细日志(临时)
SET GLOBAL innodb_print_all_deadlocks = ON;
SET GLOBAL innodb_status_output_locks = ON;
2. 查看死锁信息
-- 查看最近死锁信息
SHOW ENGINE INNODB STATUS\G;
-- 查看错误日志中的死锁记录
-- 错误日志位置:SHOW VARIABLES LIKE 'log_error';
二、分析死锁信息
死锁日志通常包含以下关键部分:
LATEST DETECTED DEADLOCK
------------------------
1) TRANSACTION: trx_id 12345
Locks held: 记录持有的锁
Locks waiting: 记录等待的锁
2) TRANSACTION: trx_id 67890
Locks held: 记录持有的锁
Locks waiting: 记录等待的锁
*** WE ROLL BACK TRANSACTION trx_id 12345
三、监控工具
1. 查询死锁相关信息(MySQL 5.7)
-- 启用死锁监控
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE '%events_transactions%';
-- 查询死锁相关信息
SELECT * FROM information_schema.INNODB_TRX;
SELECT * FROM information_schema.INNODB_LOCKS;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
2. 查看锁等待关系(MySQL 5.7)
-- 查看正在执行的事务
SELECT * FROM information_schema.INNODB_TRX;
-- 查看锁等待关系
SELECT
r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM information_schema.INNODB_LOCK_WAITS w
INNER JOIN information_schema.INNODB_TRX b
ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.INNODB_TRX r
ON r.trx_id = w.requesting_trx_id;
从 MySQL 8.0 开始,INFORMATION_SCHEMA.INNODB_LOCKS 和 INFORMATION_SCHEMA.INNODB_LOCK_WAITS 这两个表已经被移除了。以下是 MySQL 8.0+ 的替代方案:
3. 查询死锁相关信息(MySQL 8.0+)
3.1. 使用 performance_schema 相关表
-- 查看数据锁信息(替代 INNODB_LOCKS)
SELECT * FROM performance_schema.data_locks;
-- 查看数据锁等待信息(替代 INNODB_LOCK_WAITS)
SELECT * FROM performance_schema.data_lock_waits;
-- 查看元数据锁信息
SELECT * FROM performance_schema.metadata_locks;
3.2. 使用 sys 系统库(更友好的视图)
-- 查看当前锁等待情况(推荐使用)
SELECT * FROM sys.innodb_lock_waits;
-- 查看详细的锁信息
SELECT * FROM sys.x$innodb_lock_waits;
-- 查看会话的锁信息
SELECT * FROM sys.session WHERE trx_state = 'LOCK WAIT'\G
4. 查看锁等待关系(MySQL 8.0+)
-- 方式1:使用 sys 库(最简洁)
SELECT
waiting_trx_id,
waiting_pid,
waiting_query,
blocking_trx_id,
blocking_pid,
blocking_query,
wait_age,
sql_kill_blocking_query
FROM sys.innodb_lock_waits;
-- 方式2:使用 performance_schema
SELECT
r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM performance_schema.data_lock_waits w
INNER JOIN information_schema.INNODB_TRX b
ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
INNER JOIN information_schema.INNODB_TRX r
ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID;
四、预防和解决策略
1. 事务设计优化
-
保持事务简短
-
按固定顺序访问多个表
-
避免大事务
-
使用合适的隔离级别
2. SQL优化
-- 1. 使用索引减少锁范围
CREATE INDEX idx_column ON table(column);
-- 2. 尽量减少锁定行数
-- 避免全表扫描的UPDATE/DELETE
-- 3. 合理使用锁提示
SELECT ... FOR UPDATE -- 排他锁
SELECT ... LOCK IN SHARE MODE -- 共享锁
-- 4. 使用NOWAIT或SKIP LOCKED(MySQL 8.0+)
SELECT ... FOR UPDATE NOWAIT;
SELECT ... FOR UPDATE SKIP LOCKED;
3. 应用层策略
-
实现重试机制
-
设置合理的锁等待超时
SET innodb_lock_wait_timeout = 50; -- 设置锁等待超时(秒)
五、排查步骤总结
-
收集信息:查看错误日志和
SHOW ENGINE INNODB STATUS -
识别模式:分析死锁涉及的SQL、表和索引
-
重现问题:尝试在测试环境重现
-
优化方案:
-
调整事务顺序
-
添加缺失索引
-
修改SQL语句
-
调整隔离级别
-
-
监控验证:部署后持续监控
六、常用命令汇总
# 查看当前死锁频率
mysql> SHOW STATUS LIKE 'innodb_row_lock%';
# 查看锁等待信息
mysql> SELECT * FROM sys.innodb_lock_waits;
# 查看线程信息
mysql> SHOW PROCESSLIST;
mysql> SELECT * FROM performance_schema.threads;
通过以上方法,可以系统性地排查和解决MySQL事务死锁问题。建议先从死锁日志入手,识别出具体的锁争用模式,然后针对性地优化事务设计和SQL语句。
更多推荐


所有评论(0)