触发器本质是“表级自动钩子”
触发器不是独立运行的程序,而是绑定在某张表上的、由
INSERT、
UPDATE或
DELETE操作自动唤起的一段 SQL 逻辑。它不接受调用,也不依赖应用层——只要 DML 动作发生,且满足定义条件(比如“在 user 表插入前”),就立刻执行。它的底层机制和存储过程类似,但关键区别在于:**没有显式调用入口,只有事件驱动入口**。
BEFORE 和 AFTER 的实际影响远不止“前后”字面意思
BEFORE触发器能读写
NEW(新行数据),甚至修改它——比如把空
age改成
0,或拦截非法值并报错(用
SIGNAL SQLSTATE '45000');而
AFTER只能读
NEW和
OLD,不能改当前操作的数据,但适合做日志记录、跨表同步这类“事后动作”。注意:
BEFORE DELETE中只能访问
OLD,
AFTER INSERT中没有
OLD——这些限制一旦写错,会直接导致语法错误或逻辑失效。
典型使用场景与真实风险点
常见用途有三类,但每类都藏着隐性成本:
数据校验(如订单金额 ≥ 0):用BEFORE INSERT/UPDATE+
SIGNAL实现,但 MySQL 不支持事务内部分回滚,整个语句会失败,需应用层配合重试逻辑 操作日志(如往
user_logs插入记录):必须用
AFTER,否则日志可能写入但主表插入失败,造成数据不一致 级联更新(如下单减库存):看似方便,但若订单表批量插入 1000 行,触发器会执行 1000 次单条
UPDATE,极易拖慢性能——此时更推荐用应用层事务或定时任务补偿
一张表最多允许 6 个触发器(
BEFORE/AFTER × INSERT/UPDATE/DELETE),超量会报错
ERROR 1359 (HY000): Trigger already exists;另外,
LOAD DATA和
REPLACE也会激活对应类型的触发器,这点常被忽略。
查看、删除与调试必须掌握的三条命令
开发中遇到触发器不生效,先确认它是否真的存在且没被覆盖:
查所有触发器:SHOW TRIGGERS LIKE 'user';看创建语句(含 timing/event/table):
SHOW CREATE TRIGGER trigger_insert_person;删掉重来(避免命名冲突):
DROP TRIGGER IF EXISTS trigger_insert_person;
别忘了改分隔符——
DELIMITER //是写多语句触发器的前提,漏掉会导致语法解析中断,错误信息往往指向
BEGIN行而非真正问题点。
触发器最危险的地方不是写错逻辑,而是它静默运行、脱离应用监控体系。上线前务必验证它在批量操作、异常输入、并发写入下的行为,否则故障时连日志都找不到源头。
