mysql 5.7 支持单表多个同类型触发器,因触发器元数据迁入事务安全的data dictionary(innodb系统表),并引入follows/precedes显式控制执行顺序。

MySQL 5.7 确实支持单表多个同类型触发器(比如两个 AFTER INSERT),而 5.6 及更早版本会直接报错 ERROR 1359 (HY000): Trigger already exists。这不是语法糖或兼容补丁,而是底层元数据存储和触发器调度机制的实质性重构。
触发器元数据从 frm 文件迁移到 data dictionary
MySQL 5.7 引入了统一的、事务安全的 data dictionary(数据字典),将原本分散在 .frm 文件、mysql.triggers 表甚至内存中的触发器定义,全部收归到 InnoDB 系统表中(如 mysql.triggers)。这意味着:
-
mysql.triggers表现在有完整主键(TRIGGER_CATALOG, TRIGGER_SCHEMA, TRIGGER_NAME),允许同一表下存在多个不同名称的触发器 - 触发器定义不再依赖文件系统一致性,可参与事务回滚(虽然触发器本身不能回滚,但其创建/删除操作可以原子化)
- 旧版靠
.frm文件隐式约束“一个事件一个触发器”,5.7 后该约束被显式逻辑替代
FOLLOWS 和 PRECEDES 是调度顺序的显式控制手段
仅靠创建时间排序不可靠(比如重建表、导入 dump 时顺序丢失),所以 5.7.2+ 加入了执行顺序显式声明能力:
- 新建触发器时必须用
FOLLOWS existing_trigger_name或PRECEDES existing_trigger_name指定相对位置 - 不指定时默认追加到同类触发器末尾,但这个“末尾”是基于当前字典状态计算的,不是创建时间戳
- 若引用的
existing_trigger_name不存在,语句直接失败,不会静默忽略 -
SHOW CREATE TRIGGER不显示顺序信息,得查INFORMATION_SCHEMA.TRIGGERS的EVENT_MANIPULATION+ACTION_ORDER字段
同一事件多个触发器的实际执行行为
即便语法通过、顺序设好,仍需注意运行时表现:
- 所有匹配的触发器都会执行,没有短路机制 —— 一个触发器里
ROLLBACK不影响其他触发器继续执行(它们各自在独立上下文中) -
NEW和OLD在每个触发器内都是只读快照,前一个AFTER UPDATE触发器改了表数据,后一个看到的是新值,但无法修改NEW(因为已是 AFTER) - 性能开销线性增长:两个
AFTER INSERT触发器,插入一行就会触发两次完整 SQL 解析+执行流程 - 调试困难:错误日志只报出错的触发器名,不提示它在整个链中的位置,得手动查
ACTION_ORDER
真正容易被忽略的点是:MySQL 8.0 进一步强化了 data dictionary 的完整性校验,如果从 5.7 升级到 8.0,且触发器顺序依赖未显式声明(靠创建时间隐式排序),升级过程可能因字典不一致而中断 —— 所以哪怕还在用 5.7,也建议所有新增触发器都带上 FOLLOWS/PRECEDES。











