直接查information_schema.innodb_trx可精准识别持锁长事务:trx_state='running'且trx_started超60秒、trx_rows_locked>1000或trx_lock_structs>0,即为高风险持锁源;需关联processlist确认用户与sql,避免误杀。

直接查 INFORMATION_SCHEMA.INNODB_TRX,别只盯着 SHOW PROCESSLIST——它显示的是连接状态,不是事务锁持有实况。
怎么看谁在持锁不放?
长事务真正危险的地方,是它“看起来安静”,但锁一直没释放。比如应用执行了 BEGIN,只跑了一条 SELECT ... FOR UPDATE 就断开,连接在 PROCESSLIST 里是 Sleep,但在 INNODB_TRX 里仍是 TRX_STATE = 'RUNNING'。
-
TRX_STARTED距今超 60 秒,且TRX_STATE = 'RUNNING'→ 高风险候选 -
TRX_ROWS_LOCKED > 1000或TRX_LOCK_STRUCTS > 0→ 确实占着锁资源 -
TRX_WAITING_TRX_ID IS NOT NULL→ 它自己也在等别人,但同时又在阻塞别人 - 结合
INFORMATION_SCHEMA.PROCESSLIST关联TRX_MYSQL_THREAD_ID = ID,看USER、HOST、INFO,确认是不是某个服务实例或 DBA 终端遗留的连接
为什么 sys.schema_table_lock_waits 有时查不到阻塞源?
这个视图只显示「正在发生」的元数据锁(MDL)阻塞,对 InnoDB 行锁无效;而且它不捕获 Sleep 状态的悬挂事务——只要连接没发新命令,它就不出现在结果里。
- 返回空 ≠ 没锁,先确认
performance_schema已启用:SELECT @@performance_schema;应为 1 - 若怀疑是 MDL 锁,需额外开启采集器:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; - 真正卡住 DDL(如
ALTER TABLE)的,往往是那种Command = 'Sleep'但trx_state = 'RUNNING'的事务,必须靠INNODB_TRX+PROCESSLISTJOIN 才能揪出来
KILL 之前必须确认的三件事
杀错线程可能让问题更糟,尤其在连接池场景下。
- 用
KILL TRANSACTION <code>TRX_ID(MySQL 5.7+),不是KILL <code>ID—— 前者只终结事务,后者会干掉整个连接,可能中断其他正常请求 - 确认
TRX_STATE是RUNNING,不是LOCK WAIT;后者说明它已在等锁,杀它没用,得杀持锁方 - 检查
TRX_ISOLATION_LEVEL:如果是REPEATABLE READ,哪怕只执行过一次SELECT,事务一启就持有MDL_SHARED_READ,必须显式COMMIT或ROLLBACK才释放
最易被忽略的点:事务是否真的结束了,不取决于连接有没有发新语句,而取决于它有没有执行 COMMIT 或 ROLLBACK。很多“挂起”事务,根源是应用层异常退出后,连接被归还给池,但事务状态没清理——这时候光看 PROCESSLIST 的 Time 和 State 会误判。











