show engine innodb status 看不到触发器内sql,因其仅记录顶层语句,触发器操作被归入父事务且不单独显示锁来源;需结合死锁日志、performance_schema和triggers定义交叉验证才能定位隐式锁。

触发器导致的锁等待几乎从不报错,也不在 SHOW ENGINE INNODB STATUS 里显式出现——它藏在事务背后静默加锁,等你发现时,应用早已超时或死锁。
为什么 SHOW ENGINE INNODB STATUS 看不到触发器里的 SQL
MySQL 只记录客户端发起的顶层语句(比如 INSERT INTO orders),而触发器内执行的 UPDATE order_log SET status = 'done' WHERE order_id = NEW.id 被完全归入父事务上下文。InnoDB 不为它单独生成锁记录,也不会在 LATEST DETECTED DEADLOCK 或 TRANSACTIONS 段中列出该语句。
结果就是:你看到事务卡在 LOCK WAIT,TRX_QUERY 显示的是原始 INSERT,但实际阻塞点是触发器对 order_log 表的一次无索引更新。
- MySQL 5.7 中,
INNODB_TRX的trx_query字段为空或仅显示外层语句,无法反映触发器逻辑 - MySQL 8.0+ 仍不直接暴露触发器 SQL,但可通过
performance_schema.events_statements_history回溯(需提前开启对应 consumer) - 死锁日志里若出现含
NEW.或OLD.的语句(如UPDATE user_points SET balance = balance + NEW.amount),基本可锁定为触发器执行
怎么确认锁等待链来自触发器
单靠一张表查不出,必须三处线索交叉验证:
- 查
INNODB_LOCK_WAITS找出waiting_trx_id和blocking_trx_id,再用blocking_trx_id去INNODB_TRX查其TRX_STARTED时间——如果该事务已运行几十秒但TRX_QUERY为空,大概率卡在触发器里 - 看死锁日志中
HOLDS THE LOCK(S)和WAITING FOR THIS LOCK TO BE GRANTED是否同时出现主表(如orders)和另一张小表(如points_log);若points_log在两边都出现,而orders只出现在一边,说明锁热点已偏移至触发器目标表 - 用
SELECT * FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_TABLE = 'orders'查出所有相关触发器,再逐个检查定义里是否含UPDATE/DELETE/SELECT ... FOR UPDATE,尤其关注WHERE条件是否命中索引
AFTER 触发器为什么更容易引发锁等待
AFTER INSERT 执行时,新行已落盘并持有 X 锁,事务尚未提交;此时触发器再执行 DML,等于在已有锁基础上叠加新锁请求,锁持有时间被显著拉长。
-
AFTER INSERT中执行UPDATE stats SET count = count + 1 WHERE type = 'order':若type字段无索引,InnoDB 会全表扫描并加 Next-Key Lock,瞬间锁住整张stats表 -
BEFORE INSERT只能修改NEW字段值,不产生额外 DML,也就不会引入新锁(除非你主动写SELECT ... FOR UPDATE) - 多级嵌套触发器(如
AFTER INSERT → UPDATE user_points → BEFORE UPDATE → INSERT points_audit)会让锁路径不可控,MySQL 8.0+ 才能在INNODB STATUS中准确定位到内层语句
临时验证触发器是否真在锁表
别急着 DROP TRIGGER,先做最小干预验证:
- 手动开启事务:
SET autocommit = 0;,然后执行一条会触发它的INSERT - 立即查
SELECT * FROM performance_schema.data_locks WHERE OBJECT_NAME IN ('order_log', 'points_log'),确认是否有非预期的行锁或间隙锁出现在触发器目标表上 - 再查
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'LOCK WAIT',观察是否出现长时间LOCK WAIT且TRX_QUERY为空的事务 - 如果上述现象复现,基本可断定该触发器正在隐式制造锁等待——下一步就是把 DML 移出触发器,改由应用层异步或按统一锁序处理
真正难排查的从来不是“有没有锁”,而是“谁在加锁却不说”。触发器的静默性决定了它必须靠组合线索定位,而不是依赖单一视图或命令。











