可通过查询INFORMATION_SCHEMA.INNODB_TRX查看未提交事务;执行SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query FROM INFORMATION_SCHEMA.INNODB_TRX;重点关注trx_state为'LOCK WAIT'或长期'ACTIVE'的事务,trx_mysql_thread_id可关联PROCESSLIST定位线程。

查未提交事务:直接看 INFORMATION_SCHEMA.INNODB_TRX
MySQL 5.6+ 的 InnoDB 引擎会把活跃事务信息实时写入系统表 INFORMATION_SCHEMA.INNODB_TRX。只要事务没提交(COMMIT)或回滚(ROLLBACK),它就在这里挂着。
执行这条语句就能看到所有未提交事务:
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query FROM INFORMATION_SCHEMA.INNODB_TRX;
注意点:
-
trx_state = 'RUNNING'不代表一定没提交,要看trx_started时间是否异常久;真正关键的是trx_state = 'LOCK WAIT'或长期为'ACTIVE' -
trx_mysql_thread_id对应PROCESSLIST中的 ID,可用来关联查是谁在跑 - trx_query 是
NULL,说明事务里当前没执行 SQL(比如刚BEGIN就挂住了)
查锁等待关系:连查 INNODB_TRX、INNODB_LOCK_WAITS 和 INNODB_LOCKS
单看 INNODB_TRX 只能知道“谁卡着”,但不知道“卡在谁身上”。得靠 INNODB_LOCK_WAITS 把阻塞者和被阻塞者串起来。
常用诊断 SQL(MySQL 5.7 及以前):
SELECT r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query
FROM INFORMATION_SCHEMA.INNODB_TRX r
INNER JOIN INFORMATION_SCHEMA.INNODB_LOCK_WAITS w ON r.trx_id = w.requesting_trx_id
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX b ON b.trx_id = w.blocking_trx_id;注意点:
- MySQL 8.0+ 中
INNODB_LOCKS和INNODB_LOCK_WAITS已被移除,改用performance_schema.data_locks和data_lock_waits;上面 SQL 在 8.0 会报错 - 如果查询结果为空,不代表没锁争用——可能只是没有形成“等待链”,比如两个事务各自持锁又申请对方的锁(死锁已被自动检测并回滚掉一个)
-
blocking_query经常是NULL,因为阻塞者可能早已执行完 SQL,只留着事务没提交
快速定位源头:结合 SHOW PROCESSLIST 和线程 ID
光有事务 ID 不够,你得知道是哪个客户端、哪条命令、哪个用户干的。用 trx_mysql_thread_id 去匹配 SHOW PROCESSLIST 最直接。
例如,发现某个 waiting_thread = 123,就立刻执行:
SHOW PROCESSLIST WHERE ID = 123;
或者一次性关联查出完整上下文:
SELECT p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM INFORMATION_SCHEMA.INNODB_TRX t JOIN INFORMATION_SCHEMA.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE t.trx_state = 'LOCK WAIT';
注意点:
-
PROCESSLIST默认只显示当前用户自己的线程,需有PROCESS权限才能看全部 -
STATE字段值如'Updating'、'Sending data'是线索,但不能完全信任——有些状态会滞后更新 - 如果
INFO是NULL,大概率是事务内没执行新语句,或客户端用了预编译(prepared statement)且未启用log_bin_trust_function_creators等配置
MySQL 8.0 的替代方案:用 performance_schema 查锁
8.0 彻底废弃了旧的锁视图,必须转向 performance_schema。默认可能没开相关消费者,先确认:
SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE 'global_instrumentation' OR NAME LIKE 'thread%';
确保这几项是 ENABLED:
events_statements_currentdata_locksdata_lock_waits
然后查锁等待:
SELECT ENGINE_TRANSACTION_ID AS trx_id,
OBJECT_SCHEMA,
OBJECT_NAME,
INDEX_NAME,
LOCK_TYPE,
LOCK_MODE,
LOCK_DATA
FROM performance_schema.data_locks
WHERE LOCK_TRX_ID IN (
SELECT ENGINE_TRANSACTION_ID FROM performance_schema.data_lock_waits
);注意点:
- 字段名全变了:
ENGINE_TRANSACTION_ID替代trx_id,LOCK_MODE值如'X'、'S'、'REC_NOT_GAP'要查文档对应含义 -
data_lock_waits只存“正在等待”的快照,不记录历史;一旦锁释放,行就消失 - 这个路径没法直接看出 SQL 内容,得再 join
events_statements_current拿SQL_TEXT,但前提是采集已开启且没被截断
锁信息分散在多个表、版本差异大、权限控制严——别指望一条命令扫清全场。最稳的路是:先用 INNODB_TRX 找活跃事务,再按 thread_id 追到 PROCESSLIST,最后根据 MySQL 版本决定要不要切到 performance_schema 深挖锁细节。


















