mysql死锁排查:程序员实战指南
一、死锁到底是怎么发生的?
想象一个场景:事务A锁定了行1,请求行2;事务B锁定了行2,请求行1——这就是经典的循环等待死锁。MySQL会自动检测死锁并回滚代价较小的事务(通过innodb_deadlock_detect=on),但实际生产环境的死锁往往比这复杂得多。
二、死锁排查三板斧
🔍 1. 抓取死锁日志
直接执行 SHOW ENGINE INNODB STATUS,重点看 LATEST DETECTED DEADLOCK 部分。比如在一次面试中,面试官就让我现场解析这段日志:
*** (1) TRANSACTION:
TRX_ID 12345, UPDATE table_a SET ... WHERE id=1
*** (2) TRANSACTION:
TRX_ID 67890, DELETE FROM table_a WHERE id=2
*** WE ROLL BACK TRANSACTION (2)
关键信息提取:
- 冲突的SQL语句(重点关注UPDATE/DELETE/SELECT ... FOR UPDATE)
- 等待的锁类型(
lock_mode X表示排他锁) - 持有锁的资源(
space id 456 page no 3指向具体数据页)
🛠 2. 复现死锁场景
根据日志中的SQL,用脚本模拟并发操作。例如:
# 终端1
BEGIN;
UPDATE orders SET amount=100 WHERE user_id=1; -- 锁住user_id=1
# 终端2
BEGIN;
UPDATE orders SET amount=200 WHERE user_id=2; -- 锁住user_id=2
UPDATE orders SET amount=150 WHERE user_id=1; -- 等待终端1的锁
此时在终端1执行 UPDATE ... WHERE user_id=2 就会立刻触发死锁!
📊 3. 分析锁冲突根源
根据我的踩坑经验,90%的死锁由以下原因导致:
| 问题类型 | 典型案例 | 解决方案 |
|------------------|--------------------------|----------------------|
| 索引缺失 | WHERE条件无索引导致锁全表 | 添加联合索引 |
| 事务过大 | 单个事务更新500+行 | 拆分事务+分批提交 |
| 执行顺序不一致| 不同业务代码中UPDATE顺序相反 | 强制统一操作顺序 |
三、终极预防策略
- 缩短事务:执行完即时提交,避免跨HTTP请求的事务
- 降低隔离级别:用READ COMMITTED代替REPEATABLE READ(需评估业务)
- 加锁超时:设置
innodb_lock_wait_timeout=5(单位:秒) - SQL审核:强制要求WHERE条件走索引
💡 插播福利:如果你正在准备面试,推荐使用2025年Java面试宝典(提取码:9b3g),涵盖MySQL调优、分布式锁等高频考点。
四、面试如何优雅回答
当面试官问“实际项目中如何解决死锁?”时,可以这样结构化回答:
- 监控:配置报警监听
SHOW STATUS LIKE '%deadlock%' - 取证:通过
innodb_print_all_deadlocks=on记录全部死锁日志 - 止损:结合APM工具(如SkyWalking)定位热点锁冲突代码
- 根治:用
EXPLAIN验证索引使用情况,用pt-deadlock-logger自动化分析
🙋 最后打个广告:如果需要开通**面试鸭**会员(原价99元),通过 面试鸭返利网 找我可返现25元!用省下的钱买杯咖啡☕,继续肝代码不香吗?

(扫码或访问 mianshiyafanli.com 获取返利)


