真正要KILL的是持锁未提交的源头事务,而非报错线程;需查INNODB_TRX中trx_state='RUNNING'且trx_started超2分钟、trx_query为空或含SLEEP/HTTP调用的记录,再通过INNODB_LOCK_WAITS定位blocking_trx_id,KILL其对应trx_mysql_thread_id。

报 Lock wait timeout exceeded 时,真正要杀的不是报错的那个线程,而是那个开着事务、执行完 SQL 却不提交、一直霸着锁的“源头”。查不到它,改参数、重试、重启都只是临时止痛。
查 INNODB_TRX 找出“空挂”的长事务
锁等待超时的本质是:有人拿了锁不放。而 INNODB_TRX 是唯一能实时看到所有活跃事务状态的入口。重点筛出那些 trx_state = 'RUNNING' 且 trx_started 时间远早于当前时间的记录——比如已运行 2 分钟以上。
-
trx_query为空?大概率是只执行了BEGIN或上一条 SQL 已结束,但事务没COMMIT/ROLLBACK -
trx_query是SLEEP(30)、HTTP 调用、日志写入?说明事务卡在非 DB 操作上,应用层没设超时或异常后漏回滚 -
trx_mysql_thread_id是关键,它才是你要 KILL 的目标 ID,不是trx_id - Spring 应用特别容易踩坑:
@Transactional方法里调了 RPC 但没设超时,或catch异常后忘了rollback()
用 INNODB_LOCK_WAITS 确认谁在等谁
单看 INNODB_TRX 只知道“谁没提交”,但不知道“谁被它挡住了”。INNODB_LOCK_WAITS 是唯一能明确映射等待关系的视图,字段名自带因果逻辑。
- 执行
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS,如果返回空,不代表没锁——可能刚超时回滚、或锁已释放;此时要立刻重查INNODB_TRX抓快照 - 联查时用
blocking_trx_id关联到INNODB_TRX中对应记录,确认它的trx_state几乎总是RUNNING,而非LOCK WAIT -
blocking_query经常为空——因为持锁者可能早已执行完UPDATE,只是事务还开着;不能因此认为它“安全” - MySQL 8.0+ 更推荐用
sys.innodb_lock_waits,字段更直白:waiting_pid和blocking_pid直接对应SHOW PROCESSLIST中的 ID
别漏掉元数据锁(MDL)这种隐形阻塞源
如果你发现 ALTER TABLE 卡住、或者一堆 SELECT 突然集体变慢,且 INNODB_TRX 和 INNODB_LOCK_WAITS 查不到线索,大概率是 MDL 锁问题——它不会出现在行锁视图里,也不会显示在 SHOW PROCESSLIST 的 State 字段中。
- 先确认
performance_schema已启用:SELECT @@performance_schema应为ON - 查持有 MDL 的会话:
SELECT THREAD_ID FROM performance_schema.events_waits_current WHERE EVENT_NAME = 'wait/lock/metadata/sql/mdl' AND STATE = 'WAITING' - 再用该
THREAD_ID关联performance_schema.threads,查PROCESSLIST_INFO得到原始 SQL - 典型场景:一个未提交事务里执行过
SELECT,接着有人想ALTER同一张表;或FLUSH TABLES WITH READ LOCK没释放
真正难的不是命令怎么写,而是判断哪一类锁在作祟——行锁、表锁、还是 MDL。一旦方向错了,查半天 INNODB_TRX 都找不到人,因为人家根本不在那儿。定位前先看现象:报错带 Lock wait timeout?还是 Waiting for table metadata lock?这一步跳不过。


















