查innodb_trx是排查锁等待的第一步,需重点筛选trx_state='lock wait'的事务并按trx_started升序排查;trx_state='running'且command='sleep'的未提交事务更危险;innodb_lock_waits在5.7中不可靠,应结合innodb_locks和show engine innodb status定位真实阻塞者。

查 INNODB_TRX 看谁卡住了
直接查 INFORMATION_SCHEMA.INNODB_TRX 是第一步,它告诉你当前所有活跃事务的状态。重点不是“有多少事务”,而是哪些事务的 trx_state 是 'LOCK WAIT' —— 这代表它已经被堵住,正在等锁释放。
同时关注:trx_wait_started(开始等待的时间)、trx_query(它卡在什么 SQL 上)、trx_rows_locked(锁了多少行,数值异常大可能意味着锁范围失控)。如果 trx_query 为空但 trx_state = 'LOCK WAIT',大概率是客户端已断开、事务没回滚,还在后台持锁。
-
trx_started时间远早于当前时间,说明事务可能忘了提交或崩溃后残留 -
trx_isolation_level是REPEATABLE-READ时,间隙锁(GAP)和临键锁(NEXT-KEY)默认启用,容易扩大锁范围 -
trx_mysql_thread_id可直接对应SHOW PROCESSLIST中的Id,方便 kill 或追踪连接来源
用 INNODB_LOCK_WAITS 找阻塞源头
INNODB_LOCK_WAITS 是唯一能直接告诉你“谁在等谁”的表。它只返回两列核心字段:requesting_trx_id 和 blocking_trx_id。前者是你查到的 LOCK WAIT 事务 ID,后者就是真正持锁不放的那个。
注意:INNODB_LOCK_WAITS 返回空 ≠ 没有锁争用。它只记录“已进入等待状态”的关系;如果两个事务几乎同时尝试加互斥锁,一个可能被立即拒绝并报错 ERROR 1205 (HY000): Deadlock found,这种情况下不会出现在该表里。
- 必须用
blocking_trx_id去INNODB_TRX中查对应事务,看它执行了什么、是否长时间未提交 - 若
blocking_trx_id在INNODB_TRX中查不到,说明该事务已结束但锁未清理干净(极少见,多见于异常崩溃后) - 一个
blocking_trx_id可能对应多个requesting_trx_id,即一个慢事务拖垮多个并发请求
看 INNODB_LOCKS 理清锁类型和范围
INNODB_LOCKS 显示当前所有被持有的锁实例,每行对应一个锁。关键字段包括:lock_trx_id(哪个事务加的)、lock_mode(如 X,REC_NOT_GAP 表示排他记录锁,X,GAP 表示间隙锁)、lock_type(RECORD 或 TABLE)、lock_data(锁的具体值,对行锁通常是主键或唯一索引值)。
lock_data 不一定可靠:非唯一二级索引上的锁,lock_data 可能只显示部分字段;GAP 锁的 lock_data 往往为空或仅显示边界(如 1,5 表示间隙 (1,5))。
- 同一事务可能在聚簇索引和多个二级索引上分别持不同锁,比如
X,REC_NOT_GAP+X,GAP -
lock_mode出现S(共享锁)或X(排他锁)本身不危险,危险的是搭配GAP后锁住一大片“不存在的行” - 如果某条锁的
lock_trx_id对应事务已提交,但锁仍在INNODB_LOCKS中,说明 InnoDB 清理延迟,一般几秒内会自动消失
配合 SHOW ENGINE INNODB STATUS 定位死锁细节
当发生死锁时,MySQL 会选一个事务回滚,并把完整上下文写入错误日志(前提是 innodb_print_all_deadlocks=ON,5.7+ 默认开启)。但更快速的办法是执行 SHOW ENGINE INNODB STATUS\G,然后翻到 LATEST DETECTED DEADLOCK 段落。
这里会明确列出两个冲突事务的 WAITING FOR 和 HOLDS THE LOCK(S) 关系,甚至给出各自最后执行的 SQL。注意:这个输出是瞬态快照,只保留最近一次死锁信息,且不包含超时等待(仅死锁)。
- 死锁日志里出现
index `idx_status`但你没建这个索引?说明优化器走了隐式索引或统计信息过期 - 如果
WAITING FOR的是lock_mode X locks rec but not gap waiting,说明对方持的是纯记录锁,问题大概率出在业务逻辑没及时提交 - 频繁出现相同索引上的死锁,基本可判定是多个事务以不同顺序访问同一组索引——比如事务 A 先锁 id=1 再锁 id=2,事务 B 反过来
INNODB_LOCKS 和 INNODB_LOCK_WAITS 都只反映“当前瞬间”的状态,稍纵即逝;更麻烦的是,锁范围由索引结构、隔离级别、查询条件共同决定,同一句 SQL 在不同数据分布下可能锁 1 行,也可能锁 1 万行间隙——这没法靠一张表直接看出来,得结合 EXPLAIN 和实际索引定义交叉验证。











