mysql触发器什么时候执行_mysql触发时机解析

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

INSERT 触发器在 INSERT 语句真正写入表之前还是之后执行?

取决于你定义的

BEFORE INSERT
还是
AFTER INSERT
。MySQL 明确区分这两个时机:
BEFORE
在数据校验通过、但尚未写入磁盘前触发,此时能修改
NEW
行值;
AFTER
在整行已成功插入、事务尚未提交时触发,此时不能改
NEW
,但可读取自增 ID 或调用外部逻辑。

常见错误是误以为

AFTER INSERT
能修改刚插入的行——它不能,
NEW
AFTER
中是只读的。若需动态生成字段值(如拼接 code),必须用
BEFORE INSERT

CREATE TRIGGER set_user_code 
BEFORE INSERT ON users
FOR EACH ROW
SET NEW.code = CONCAT('U_', NEW.id); -- 错!id 还没生成
-- 正确做法:用 UUID() 或其他不依赖自增 ID 的方式,或改用 AFTER + UPDATE(不推荐)

UPDATE 触发器中 NEW 和 OLD 到底代表什么?

OLD
始终是更新前的原始行快照,
NEW
是即将写入的新行(
BEFORE
中可改,
AFTER
中只读)。关键点在于:即使 SQL 中只更新一个字段,
NEW
仍包含所有列值——未显式指定的列会回填原值(不是 NULL)。

判断某字段是否被修改,不能写
IF NEW.status != OLD.status
然后直接赋值,要先处理 NULL 比较(
IS NULL
/
IS NOT NULL
BEFORE UPDATE
是唯一能拦截非法变更的地方,比如禁止将
status
'done'
改回
'pending'
AFTER UPDATE
适合记录日志、更新统计表,但要注意:若触发器里再 UPDATE 同一表,可能引发递归(除非
SQL_LOG_BIN=0
或禁用嵌套)

DELETE 触发器能否访问被删行的外键关联数据?

不能直接访问。

BEFORE DELETE
中只有
OLD
,它只含本表字段;
AFTER DELETE
OLD
依然可用,但关联表的数据已不可查(除非手动 JOIN 查询,且该查询必须在事务内完成)。

典型陷阱是想在

AFTER DELETE
里做级联清理,却忘了外键约束可能已先触发(如
ON DELETE CASCADE
),导致关联行已被删,再查就为空。

需要级联操作,优先用外键
ON DELETE CASCADE
ON DELETE SET NULL
,比触发器更可靠
若必须用触发器(例如要写日志或调用存储过程),放在
BEFORE DELETE
,用
SELECT ... INTO
提前把关联数据捞出来存变量
注意隔离级别:在
REPEATABLE READ
下,
BEFORE DELETE
中查到的关联数据可能不是最新状态

触发器执行失败会导致主 SQL 失败吗?

会。MySQL 中触发器属于主 DML 语句事务的一部分,任何触发器内的错误(如除零、字段类型不匹配、违反约束)都会让整个语句回滚,并抛出明确错误,例如:

ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function or trigger.

这意味着你不能在触发器里执行

COMMIT
START TRANSACTION
,也不能调用含显式事务的存储过程。另一个常被忽略的点是性能影响:每个触发器都增加语句开销,尤其
AFTER
类型还要等写盘完成,高并发写入场景下容易成为瓶颈。

真正难调试的是隐式行为——比如某个

BEFORE INSERT
修改了
NEW.created_at
,但应用层又默认设了该字段,结果值被覆盖两次;这种逻辑耦合很难一眼发现。

相关推荐