
sql 触发器的 BEFORE 和 AFTER 本质区别在于执行时机,直接影响数据一致性、性能和逻辑可靠性。选错时机可能引发错误、死锁或绕过业务规则。
BEFORE 触发器:适合数据校验与预处理
它在语句实际修改数据前运行,能访问 OLD(UPDATE/delete)和 NEW(INSERT/UPDATE)伪记录,且允许修改 NEW 值——这是它最不可替代的能力。
- 强制字段默认值:比如 INSERT 时若未提供
created_at,在 BEFORE INSERT 中设为NOW() - 业务级约束检查:如 UPDATE 订单状态时,在 BEFORE UPDATE 中验证“仅允许从 ‘pending’ → ‘shipped’”,不合法则用
signal报错 - 敏感字段清洗:用户注册时,在 BEFORE INSERT 中自动对
email字段调用TRIM(LOWER())
AFTER 触发器:适合联动操作与审计日志
它在语句成功提交后执行,此时数据已持久化,可安全读取最终结果,但不能再修改当前行(否则会报错)。适合不干扰主事务逻辑的“善后”任务。
- 写操作日志:AFTER INSERT 记录新用户 ID、IP、时间到
user_log表 - 更新关联统计:AFTER INSERT INTO
order_items后,更新对应订单的total_amount - 异步通知准备:AFTER UPDATE 订单状态为 ‘paid’ 后,向消息队列插入一条待发送通知记录(注意:不在此处直接发 http 请求,避免阻塞事务)
别踩这些坑
实际使用中几个高频问题:
- 在 AFTER 触发器里尝试修改触发它的表(比如 AFTER INSERT 更新同一张表),多数数据库(如 mysql)会报错 “Can’t update table in stored function/trigger”
- BEFORE 触发器中误用
OLD(INSERT 没有OLD)、或NEW(DELETE 没有NEW),导致语法错误或空值异常 - 嵌套触发器失控:AFTER 触发器又 INSERT 其他表,而该表也有 AFTER 触发器……容易形成隐式递归,建议用系统变量(如 MySQL 的
@@max_sp_recursion_depth)限制深度 - 事务一致性被忽略:AFTER 触发器里的 SQL 若失败(如磁盘满、外键冲突),整个原始事务会回滚——这点常被低估,务必确保日志表结构稳定、权限充足
简单判断口诀
想改刚进来的数据?→ 用 BEFORE。
想基于最终结果做点别的事?→ 用 AFTER。
不确定?先问自己:这步操作失败了,是否必须让主 SQL 失败?是 → BEFORE;否 → AFTER。