会回滚,而且是整个事务一起回滚——不是只撤触发器里的操作,也不是只撤主语句,而是从begin(或隐式事务起点)开始的所有变更全部撤销;mysql触发器与主语句共享同一事务上下文,其错误(如signal、约束冲突)由innodb强制保障原子性,导致主语句及触发器内所有dml一并回滚。

会回滚,而且是整个事务一起回滚——不是只撤触发器里的操作,也不是只撤主语句,而是从 BEGIN(或隐式事务起点)开始的所有变更全部撤销。
MySQL 触发器和主语句共享同一个事务上下文
触发器不是独立事务,它直接运行在主语句(比如 INSERT、UPDATE)所属的事务里。只要触发器内出错——比如 SIGNAL SQLSTATE '45000'、字段名拼错(NEW.invalid_col)、违反外键或唯一约束——整个事务立刻被标记为失败,主语句和触发器中已执行的任何 DML 全部回滚。
这种行为由 InnoDB 引擎强制保障,属于原子性要求。哪怕你只在 AFTER INSERT 里往审计表写一行日志,而审计表少一个非空字段,主表那条记录也不会插入。
-
BEFORE触发器能修改NEW并提前终止;AFTER触发器不能改数据,但它的错误照样导致主语句回滚 - 默认
autocommit = 1时,单条语句就是独立事务,回滚效果“看不见”,但确实发生了 - 验证是否真回滚:先
START TRANSACTION,再执行 DML,然后查目标表和日志表,最后ROLLBACK
SQL Server 触发器里 RAISERROR 不自动回滚事务
和 MySQL 不同,SQL Server 的 RAISERROR 只是抛异常,并不等价于事务回滚。如果没紧跟 ROLLBACK TRANSACTION,上层 INSERT 可能照常提交,造成数据状态与业务逻辑严重错位。
更可靠的做法是用 THROW(SQL Server 2012+),并确保开头有 SET XACT_ABORT ON。否则即使触发器报错,事务仍处于活动状态(XACT_STATE() = 1),后续 COMMIT 会让部分数据落库。
-
RAISERROR严重级必须 ≥ 11 才能被客户端捕获;级别 10 及以下默认不中断执行流 -
THROW后语句自动终止,天然适配事务中断逻辑 - 嵌套触发器中,一次
ROLLBACK就能回滚到最外层起点,不用管@@TRANCOUNT累加
为什么不能在触发器里写 COMMIT 或 ROLLBACK?
MySQL 直接报错 ERROR 1305(SAVEPOINT, ROLLBACK, or COMMIT is not allowed in stored function or trigger);SQL Server 在触发器中显式控制事务也会引发错误或不可预期行为。
根本原因是:触发器是语句级钩子,不是事务容器。它没有自己的事务边界,只能依附于父事务。你想“局部失败不中断主流程”,MySQL 不支持自治事务,SQL Server 也不允许在触发器里开启新事务。
- MySQL 中唯一可控的中断方式是
SIGNAL(仅限BEFORE)或制造约束冲突 - SQL Server 中必须靠
ROLLBACK TRANSACTION+RETURN组合来确保终止 - 跨表更新、调用存储过程、SELECT 返回结果集等操作,在触发器里都可能直接报错(如
ERROR 1442、ERROR 1415)
最容易被忽略的静默失败点
触发器报错常常不直接透出给客户端,尤其语法类错误或路径缺失(比如只写 INSERT INTO audit_log 没带库名)。主语句失败了,应用却只收到模糊提示甚至无报错。
必须立刻执行两步定位:
- 执行完疑似失败的 DML 后,马上跑
SHOW WARNINGS(MySQL)或检查 SSMS “消息”窗口(SQL Server) - 确认错误日志是否启用:
SELECT @@log_error(MySQL),或检查sys.dm_os_error_logs(SQL Server) - 验证触发器是否真被执行:在开头加
INSERT INTO debug_log或RAISERROR('fired', 0, 1) WITH NOWAIT
真正难排查的是:触发器失败后不留痕迹,也没有通用诊断机制。出问题时得靠业务日志 + binlog 解析(MySQL)或扩展事件(SQL Server)反推,而不是查错误日志本身。











