应先查innodb_trx中trx_state='lock wait'的事务定位等待方,再通过innodb_lock_waits获取blocking_trx_id找到持锁元凶,最后kill blocking_thread释放锁,而非报错线程。

查 INNODB_TRX 找出正在等锁的事务
报错一出现,立刻连上数据库执行:SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'LOCK WAIT'。这能筛出所有卡在锁上的事务,重点关注 trx_started(开始时间)和 trx_mysql_thread_id(线程 ID)。如果 trx_started 是 5 分钟前的,说明它已经等了这么久——但别急着 kill 它,它只是“受害者”。
用 INNODB_LOCK_WAITS 关联出真正持锁的事务
INNODB_LOCK_WAITS 是关键跳板,它直接记录谁在堵谁:SELECT * FROM information_schema.INNODB_LOCK_WAITS。结果里有两个核心字段:blocking_trx_id(肇事者事务 ID)和 requested_lock_id(受害者想要的锁)。把 blocking_trx_id 拿去查 INNODB_TRX 表,就能拿到持锁事务的 trx_mysql_thread_id 和 trx_query。
常见误区:只查 SHOW PROCESSLIST。它不显示锁关系,可能看到一堆 Sleep 或 Query 状态,却不知道哪个线程正拿着行锁不放。
KILL blocking_thread,不是报错的那个线程
定位到持锁线程 ID 后,执行:KILL [blocking_thread_id]。注意:不是 kill 报错语句所在的线程,那是等锁失败的线程;kill 它毫无意义,锁还在原地。
- 如果持锁事务是手动执行后忘了
COMMIT或ROLLBACK,KILL 后会自动回滚,释放所有锁 - 如果持锁事务正在跑一个慢查询(比如没走索引的 UPDATE),KILL 能中断它,但需后续优化 SQL
- 如果持锁事务包含外部调用(HTTP、RPC、SLEEP),
trx_started时间远大于 SQL 执行耗时,基本可锁定为应用逻辑问题
为什么有时候查不到 blocking_trx_id?
查 INNODB_LOCK_WAITS 返回空,并不等于没锁问题。可能原因包括:
- 锁已释放:报错发生后几秒内没及时查,持锁事务刚好提交或超时断开
- 其实是死锁:InnoDB 已自动检测并回滚一方,此时应查
SHOW ENGINE INNODB STATUS\G中的LATEST DETECTED DEADLOCK区块 - 元数据锁(MDL)阻塞:STATE 显示
Waiting for table metadata lock,这时要查performance_schema.metadata_locks,跟行锁无关 - MySQL 8.0+ 且未启用
performance_schema相关 instrument,部分锁信息不可见
真正难的不是查到那一行 SQL,而是判断它为什么迟迟不提交——是索引缺失导致扫描太慢?事务里混了同步 HTTP 请求?还是开发在客户端工具里改了两行就走开了?这些不会写在 trx_query 里,得结合 trx_started 时间戳和应用日志交叉验证。











