MySQL死锁排查实战:show engine innodb status详解

Mei Lin | 2026-08-23T04:07:00 | Java, Database

线上MySQL频繁死锁,通过show engine innodb status和gap lock分析找到根因并解决

# MySQL死锁排查实战:show engine innodb status详解 线上服务频繁报`Deadlock found when trying to get lock`,数据库死锁了。 ## 查看死锁信息 ```sql -- 这条命令是排查死锁的核武器 SHOW ENGINE INNODB STATUS; -- 输出的LATEST DETECTED DEADLOCK部分: -- *** (1) TRANSACTION: -- HOLDS lock on index PRIMARY, space id 42 -- WAITING FOR lock on index idx_user_id -- -- *** (2) TRANSACTION: -- HOLDS lock on index idx_user_id, space id 42 -- WAITING FOR lock on index PRIMARY ``` 经典的AB-BA死锁:事务1拿了主键锁等二级索引锁,事务2拿了二级索引锁等主键锁。 ## 根因分析 ```sql -- 事务1:先更新订单状态,再插入日志 BEGIN; UPDATE orders SET status = 'paid' WHERE id = 100; -- 锁主键 INSERT INTO order_logs (order_id, action) VALUES (100, 'pay'); -- 锁二级索引 -- 事务2:并发操作同一订单 BEGIN; UPDATE order_logs SET status = 1 WHERE order_id = 100; -- 锁二级索引 UPDATE orders SET amount = 200 WHERE id = 100; -- 锁主键 -- 死锁! ``` ## 解决方案 ```sql -- 方案1:统一加锁顺序(推荐) -- 所有事务都先锁orders再锁order_logs -- 方案2:减小锁粒度 -- 把两个UPDATE拆成独立事务 -- 方案3:设置超时自动回滚 SET innodb_lock_wait_timeout = 5; -- 等锁超过5秒自动放弃 ``` 还有个隐蔽的坑:**Gap Lock**。在RR隔离级别下,范围查询会锁住间隙,很容易造成意想不到的死锁。遇到频繁死锁,考虑降级到RC隔离级别。

← Back to Blog