mysql触发器是“自动响应表操作的SQL小管家”,在INSERT、UPDATE、delete事件发生时,无需调用即在同一事务中执行预设逻辑。

mysql触发器到底是个啥?一句话说清
MySQL触发器就是一个“自动响应表操作的SQL小管家”:你往表里 INSERT 一条数据、改了某行 UPDATE、或者删掉记录 DELETE,它就立刻按你写好的逻辑偷偷执行一段SQL——不用调用、不靠应用层、也不需要手动跑,只要事件发生,它就在同一事务里跟着动。
什么时候非得用触发器?不是所有场景都适合
触发器真有用,但容易被滥用。它最适合解决那些“必须在数据库层强约束、且跨表联动”的问题:
- 订单插入时自动生成带前缀+补零的单号(
BEFORE INSERT+NEW.order_number赋值) - 用户余额更新后,自动往日志表写一条变更记录(
AFTER UPDATE+INSERT INTO audit_log...) - 删除商品前,检查是否还有未完成订单,有则报错回滚(
BEFORE DELETE+if EXISTS ... THEN signal SQLSTATE '45000' ...) - 库存扣减后,若低于阈值,自动更新
is_low_stock = 1字段(AFTER UPDATE跨字段联动)
⚠️ 别用它做耗时操作(比如发邮件、调外部API)、别嵌套调用存储过程、更别指望它替代应用层的业务校验——事务一崩,整个操作就撤回,连带你的“成功提示”都是假的。
创建触发器最容易栽的三个坑
写法看着简单,实操中翻车率极高,尤其新手常卡在这三点:
- 没改分隔符就写多行:MySQL默认以
;结束语句,但触发器体里也有;,不先执行DELIMITER $$,就会报错Error 1064—— 一定要在CREATE TRIGGER前改,结束后再改回来 - 混淆 NEW 和 OLD:只有
INSERT能用NEW(新数据),DELETE只能用OLD(旧数据),UPDATE两者都能用(NEW是改后值,OLD是改前值)。写成OLD.id在INSERT里直接报错 - 同一张表上重复建同类型触发器:一张表最多只能有一个
BEFORE INSERT、一个AFTER UPDATE……共6个。想覆盖旧的?先DROP TRIGGER IF EXISTS trigger_name
触发器执行时机选 BEFORE 还是 AFTER?看你要干啥
这决定你能不能改数据、能不能看到最终结果:
-
BEFORE:能修改即将插入/更新的行(通过SET NEW.xxx = ...),适合做数据清洗、默认值填充、合法性拦截;但看不到其他行的最终状态(比如不能查本表当前最大ID再+1,可能并发冲突) -
AFTER:不能改NEW或OLD的字段,但能安全读写其他表、记录日志、触发级联更新——因为主操作已落地,事务还没提交,一切还在可控范围内
比如要实现“用户注册后自动创建默认配置”,必须用 AFTER INSERT;而“插入时强制转小写邮箱”,就得用 BEFORE INSERT 改 NEW.email。
触发器不是银弹,它是把双刃剑:用对了,数据一致性稳如磐石;用错了,排查链路变长、性能毛刺频出、甚至引发死锁。关键不在会不会写,而在清楚知道——这一行SQL,到底该由谁来负责保证正确。