mysql触发器before和after有什么区别_mysql执行顺序说明

来源:这里教程网 时间:2026-02-28 20:42:06 作者:

BEFORE 触发器能改数据,AFTER 不能

这是最核心的区别:在

BEFORE INSERT
BEFORE UPDATE
中,你可以安全地修改
NEW
行的字段值,这些修改会真正写入表;而
AFTER
触发器里,
NEW
是只读的——你试图赋值会报错:
ERROR 1362 (HY000): Updating of NEW row is not allowed in after trigger

BEFORE
中可写:
SET NEW.created_at = NOW(), NEW.email = LOWER(NEW.email);
AFTER
中写同句 → 直接报错
DELETE
没有
NEW
,只有
OLD
INSERT
没有
OLD
,只有
NEW
UPDATE
两者都有

执行顺序决定能不能“拦住非法操作”

MySQL 的执行链条是严格线性的:BEFORE → 实际 DML → AFTER。这意味着:

BEFORE
在语句执行前介入,可以用
IF
+
SIGNAL
主动中止整个操作(比如年龄为负就拒绝插入)
AFTER
永远在成功提交后才运行,哪怕你想“回滚”,也已经晚了——它无法阻止主操作发生
典型翻车场景:
AFTER INSERT
更新库存,但订单插入时库存已不足 → 爆库;换成
BEFORE INSERT
先查库存再决定是否放行,才能守住一致性

什么时候必须用 BEFORE,什么时候只能用 AFTER

选错时机不是语法错误,而是逻辑漏洞。关键看你要做什么:

必须用
BEFORE

– 自动填充默认值(如
id
created_at

– 格式化输入(转小写、去空格、脱敏)
– 数据校验并中断非法写入
只能用
AFTER

– 写审计日志(要确保主操作已落地)
– 更新统计表(如销量+1,需确认订单真实插入)
– 调用外部系统(如发消息),不能因下游失败拖垮主事务
DELIMITER $$
CREATE TRIGGER order_before_check
  BEFORE INSERT ON orders
  FOR EACH ROW
BEGIN
  IF NEW.quantity > (SELECT stock FROM products WHERE id = NEW.product_id) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient stock';
  END IF;
END$$
DELIMITER ;

别忽略事务边界和性能影响

触发器天然运行在主 DML 所在事务中,这点极易被忽视:

BEFORE
AFTER
都受同一事务控制:主语句回滚,触发器所有操作也一并回滚
AFTER
里做耗时操作(如远程 HTTP 请求、大表 JOIN)会拖慢主事务,增加锁持有时间
所有触发器都禁止调用存储函数以外的非确定性函数(如
NOW()
可用,
UUID()
在某些版本受限)
MySQL 8.0+ 支持多触发器同类型排序(
FOLLOWS
/
PRECEDES
),但多数业务应避免依赖顺序,尽量单触发器闭环

真正难的从来不是语法,而是想清楚:这一步动作,是该“卡在门口检查”,还是“等进门后再记一笔”。顺序错了,数据就不可信。

相关推荐