查innodb_trx可直接获取活跃事务及锁等待状态,其中trx_state为'lock wait'或trx_wait_started非空表示正在等待锁,结合innodb_lock_waits可定位阻塞者,trx_started时间过长则提示未提交事务。

查 INFORMATION_SCHEMA.INNODB_TRX 获取活跃事务和锁等待状态
MySQL 5.6+ 的 INFORMATION_SCHEMA.INNODB_TRX 是定位锁源头最直接的入口。它不只展示“谁在等锁”,更关键的是提供 TRX_STATE、TRX_WAIT_STARTED、TRX_MYSQL_THREAD_ID 这些字段,能快速区分是“正在运行”还是“卡在等锁”。
执行以下查询可筛出疑似锁源头的事务:
SELECT TRX_ID, TRX_STATE, TRX_MYSQL_THREAD_ID, TRX_QUERY, TRX_WAITING_LOCK_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT' OR TRX_WAIT_STARTED IS NOT NULL;
注意:TRX_WAITING_LOCK_ID 非空表示该事务正在等待某个锁;但真正持锁的事务未必出现在结果里——它可能已提交、或状态仍是 RUNNING 且没显式等待。
关联 INFORMATION_SCHEMA.INNODB_LOCK_WAITS 找到阻塞者
INNODB_LOCK_WAITS 是连接“等待者”和“持有者”的桥梁,但它只记录当前等待关系,不存历史。关键字段是 BLOCKING_TRX_ID 和 REQUESTING_TRX_ID。
常用组合查询如下:
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;
常见陷阱:
- 如果
INNODB_LOCK_WAITS返回空,不代表没锁争用——可能锁已释放,或事务未进入等待态(比如被innodb_lock_wait_timeout中断) -
blocking_query可能为NULL:说明持有锁的事务没在执行 SQL(例如刚开启事务后执行了SELECT ... FOR UPDATE就挂起) - 某些隐式锁(如唯一键冲突触发的锁)不会出现在
INNODB_LOCK_WAITS中,需结合INNODB_LOCKS(MySQL 8.0 已弃用)或performance_schema.data_locks分析
用 performance_schema.data_locks 看具体行/页级锁(MySQL 8.0+)
MySQL 5.7 引入 performance_schema 锁视图,8.0 后推荐用 data_locks 替代旧的 INNODB_LOCKS。它能精确到表名、索引名、甚至锁定的主键值(LOCK_DATA 字段)。
典型用法:
SELECT ENGINE_TRANSACTION_ID, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_DATA FROM performance_schema.data_locks WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table';
关键点:
-
LOCK_DATA显示被锁的具体值(如'123'或'123', 'abc'),但仅对聚簇索引或唯一索引有效;普通二级索引可能显示为NULL - 同一
ENGINE_TRANSACTION_ID可能对应多行锁记录,说明该事务锁了多个资源 - 必须确保
performance_schema已启用,且data_locks消费器已打开:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'global_instrumentation';
别漏掉隐式锁和长事务:INNODB_TRX 中 TRX_STARTED 时间很关键
很多锁问题不是由 SQL 写错导致,而是事务开启太久却没提交。这时 TRX_STARTED 比 TRX_WAIT_STARTED 更有诊断价值。
查超时未提交事务:
SELECT TRX_ID, TRX_MYSQL_THREAD_ID, TRX_STARTED, TIMEDIFF(NOW(), TRX_STARTED) AS duration, TRX_QUERY FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_STATE = 'RUNNING' AND TIMEDIFF(NOW(), TRX_STARTED) > '00:05:00';
容易被忽略的细节:
- 应用层开启事务后忘记
COMMIT或ROLLBACK,哪怕只执行了一条SELECT ... FOR UPDATE,也会持续持锁 - 客户端连接异常断开(如网络闪断),MySQL 不会自动回滚事务,除非启用了
wait_timeout或interactive_timeout且连接空闲超时 -
TRX_QUERY为空不代表没操作——可能是事务内只做了 DML 未执行新语句,或语句已执行完毕但事务仍开着
锁源头往往不在报错那一刻的 SQL,而在几分钟前那个没关掉的事务里。











