应查information_schema.innodb_trx中trx_state='lock wait'的事务,再通过innodb_lock_waits关联blocking_trx_id定位持锁方;kill connection而非kill query才能释放锁。

怎么查出正在等锁和持锁的事务
死锁发生后,InnoDB 通常已自动回滚一个事务,但残留的锁或未提交的长事务仍会阻塞后续操作。不能只看 SHOW PROCESSLIST 里 State 是 Locked 就动手——那只是锁等待,不等于死锁源头。
真正该查的是事务级视图:
- 先执行
SELECT trx_id, trx_mysql_thread_id, trx_query, trx_state, trx_started FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'LOCK WAIT',找出正在等锁的事务 - 再关联
INFORMATION_SCHEMA.INNODB_LOCK_WAITS,查blocking_trx_id对应的trx_mysql_thread_id,它就是持锁方 - 如果查不到
LOCK WAIT状态,说明死锁已被自动处理,当前卡顿大概率是锁等待超时(Lock wait timeout exceeded)或元数据锁(MDL)阻塞
KILL CONNECTION 还是 KILL QUERY?必须分清
KILL QUERY <code>thread_id 只终止当前语句,连接还活着,事务没回滚——锁依然持有,对死锁无效,甚至让问题更隐蔽。
KILL CONNECTION <code>thread_id(MySQL 5.7+ 推荐写法,等价于旧版 KILL <code>thread_id)才会强制断开连接,触发事务回滚并释放所有锁。
执行后立刻跑 SHOW PROCESSLIST,确认该 ID 消失;若状态变成 Killed 却迟迟不退出,说明它在回滚大事务,只能等。
注意:KILL 对 SYSTEM USER 线程(如复制 IO 线程)无效,也不能杀掉自己当前连接的 thread_id。
执行 KILL 前必须核对的三件事
90% 的“误杀”都源于没验证这三项:
- 线程是否还在活跃:查
SHOW PROCESSLIST,确认对应 ID 的State是Updating、Sending data或Locked,而不是Sleep - SQL 是否可安全中断:比如
UPDATE被 KILL 会回滚,但若事务已修改上万行,回滚本身要几十秒;而ALTER TABLE被杀可能留下临时表或元数据损坏 - 连接归属是否明确:检查
User和Host字段,排除 DBA 手动执行的诊断查询、备份工具(如mydumper)、或应用健康检查连接
常见假死锁场景及应对方式
很多所谓“死锁”其实是其他锁机制导致的卡顿:
-
ALTER TABLE被SELECT阻塞:那是元数据锁(MDL),KILL 那个SELECT线程才有效,不是ALTER发起者 - 事务里只执行了
START TRANSACTION但没提交:后面所有操作都算在同一个事务里,trx_query可能为NULL,得靠trx_started时间判断陈旧度 - 用了
READ COMMITTED隔离级别却仍遇到锁等待:InnoDB 行锁在 RC 下仍存在,只是不加间隙锁,不代表完全无锁
真正难处理的,是那些 KILL 后卡在 Rolling back 状态的线程——此时硬等比强杀更安全,避免 InnoDB 状态不一致。











