会回滚,而且是整个事务一起回滚——不是只回滚触发器里的操作,也不是只回滚原SQL,而是从BEGIN(或自动开启的隐式事务起点)开始的所有变更全退回去。

会回滚,而且是整个事务一起回滚——不是只回滚触发器里的操作,也不是只回滚原 SQL,而是从 BEGIN(或自动开启的隐式事务起点)开始的所有变更全退回去。
触发器失败 = 原语句失败 = 整个事务回滚
MySQL 触发器没有独立事务上下文,它和触发它的那条 INSERT/UPDATE/DELETE 共享同一个事务。只要触发器里抛出错误(比如 SIGNAL SQLSTATE '45000'、违反外键、对 NEW 字段赋非法值、调用不存在的函数),整个语句立即中止,且已执行的修改(包括原语句本身 + 触发器中已完成的逻辑)全部回滚。
- 哪怕你只写了
BEFORE INSERT,并在里面做了几行SET NEW.x = ...,最后一行突然SELECT 1/0,整条INSERT就不会落库 -
AFTER触发器也一样:即使原语句已写入本表,触发器里去更新另一张表时失败,本表那行也会被撤回 - 不支持在触发器里用
COMMIT或ROLLBACK,MySQL 直接报错ERROR 1305 (42000): SAVEPOINT does not exist类似提示
为什么不能在触发器里改本表
MySQL 明确禁止在触发器中对“正在被操作的同一张表”执行 INSERT/UPDATE/DELETE,否则报错 ERROR 1442 (HY000): Can't update table 't' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
- 这不是性能限制,是事务可见性与锁机制冲突导致的硬性限制
- 想绕开?只能把逻辑提到应用层,或改用事件(
EVENT)+ 延迟处理,但会丢失原子性保证 - 常见误操作:在
BEFORE UPDATE里查本表做校验 → 没问题;但顺手UPDATE t SET y=... WHERE id=NEW.id→ 立刻报错
复制场景下触发器失败更危险
主从复制中,如果主库触发器失败导致事务回滚,从库可能因 binlog 格式问题产生不一致:
- 用
STATEMENT格式:触发器逻辑不记录进 binlog,从库根本不会执行,但主库已回滚 → 表面看“没动”,实际主从状态可能错位 - 必须用
ROW格式:binlog 记录的是行变更,触发器失败后主库回滚,binlog 也不生成 → 从库同步滞后但不会错乱 - 所以线上环境配主从,
binlog_format=ROW是底线,否则触发器一崩,从库数据就不可信
真正容易被忽略的是:触发器失败不会留下日志痕迹(除非你手动 INSERT INTO log_table),也没有类似 GET DIAGNOSTICS 的通用捕获机制(MySQL 8.0+ 才支持有限诊断,且仅限存储过程内)。一旦出问题,得靠业务侧日志 + binlog 解析反推,而不是查 MySQL 错误日志。


















