一眼识别mysql死锁:执行show engine innodb status\g,查看末尾latest detected deadlock区块,确认是否真死锁(含事务回滚记录),而非单纯锁等待或超时。

怎么一眼看出MySQL正在死锁
死锁发生时,应用层通常表现为某条SQL卡住不动、超时报错 Deadlock found when trying to get lock,但数据库本身还在运行——这不是宕机,是“僵持”。别急着重启,先确认是不是真死锁。
最直接的办法是查InnoDB最近一次死锁快照:
SHOW ENGINE INNODB STATUS\G这个命令输出很长,重点盯住末尾的
LATEST DETECTED DEADLOCK 区块。它会明确告诉你:哪两个事务、各自执行了什么SQL、锁住了哪些索引、谁被选为牺牲者(已回滚)。常见误判点:
- 看到一堆
Locked table就以为是死锁?错,那只是普通锁等待,还没到死锁阶段 -
show processlist里出现Locked状态,不等于死锁;死锁一定伴随至少一个事务被自动回滚,且错误日志里有明确记录 - 应用报
Lock wait timeout exceeded,大概率是锁等待超时,不是死锁(除非同时看到Deadlock关键字)
如何快速定位并干掉肇事事务
如果 SHOW ENGINE INNODB STATUS 显示死锁刚发生,但业务还在卡,说明可能有残留长事务没释放锁。这时候得手动干预。
三步定位法:
- 查当前活跃事务:
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5\G
重点关注trx_state = 'RUNNING'且trx_started时间异常早的(比如几分钟前就开了没提交) - 结合
show processlist,找出对应ID字段(即trx_mysql_thread_id),看它的State是不是Updating或Sending data卡在某条语句上 - 确认无误后,用
KILL <font color="red">thread_id</font>强制终止(注意不是KILL QUERY,要杀整个连接)
⚠️ 容易踩的坑:KILL 错了线程,可能中断正常业务;务必核对 trx_query 内容和客户端IP,避免误杀。
为什么不能只靠自动回滚,还得人工介入
InnoDB确实会自动检测死锁并回滚其中一个事务,但这是“事后补救”,不是“实时解围”。问题在于:
- 自动回滚只作用于触发死锁的那两个事务,而它们可能已经阻塞了下游几十个等待锁的事务,形成“锁链式堵塞”
-
innodb_lock_wait_timeout默认是50秒,意味着一个事务可能卡49秒才超时,期间所有依赖它的操作全挂起 - 某些场景下(如大事务+间隙锁+范围更新),死锁可能高频复现,自动机制治标不治本
所以,线上一旦发现死锁频发,必须立刻查 information_schema.innodb_trx 和 information_schema.innodb_lock_waits(MySQL 8.0+),而不是等它自己扛。
恢复后必须马上检查的三件事
kill完线程只是止血,真正的修复在后面:
- 翻错误日志(
mysqld.err),确认有没有连续多条Deadlock记录——如果有,说明逻辑缺陷没解决,还会复发 - 检查出问题的SQL是否走了索引:
EXPLAIN FORMAT=TREE your_sql
特别留意type是不是range或index,避免全表扫描放大锁范围 - 看事务里有没有隐式开启又没提交的读操作,比如先
SELECT ... FOR UPDATE,中间调用外部服务耗时几秒,再更新——这种最容易成“锁持有大户”
死锁不是随机事件,是并发逻辑和索引设计共同暴露的信号。查完日志、杀完线程、跑完explain,如果还不知道哪段代码在反复抢同一组主键+索引区间,那就只是把火扑灭,没拆引信。











