触发器是MySQL中与表绑定的事件驱动机制,在INSERT、UPDATE或DELETE时自动执行;它不可显式调用、不支持事务控制语句,BEFORE可修改NEW值,AFTER适合日志记录,性能开销需谨慎评估。
触发器是 MySQL 中一种特殊的存储程序,它在特定表上发生 INSERT、UPDATE 或 DELETE 操作时自动执行,无需应用层调用。它不是函数也不是存储过程,而是一段与表强绑定的、事件驱动的逻辑。
常见错误现象:执行 INSERT 后发现数据“莫名”被改了,或日志表没写入——大概率是触发器在后台生效但未被察觉。
BEFORE INSERT)只能有一个同类型触发器NEW / OLD)START TRANSACTION),但会参与外层语句的事务BEFORE 触发器在语句实际执行前运行,可修改 NEW 行值;AFTER 在语句成功提交后运行,适合记
录日志或同步更新其他表。
典型误用:在 AFTER UPDATE 里试图修改本表数据,会报错 Can't update table 't' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
BEFORE INSERT:可用于设置默认值、校验字段(如把空邮箱转为 'unknown@example.com')BEFORE UPDATE:适合自动更新 updated_at 字段,或阻止非法状态变更(如 status 从 'done' 改回 'pending')AFTER DELETE:常用于归档删除记录到历史表,或清理关联缓存键NEW 代表新行数据(INSERT 和 UPDATE 可用),OLD 代表旧行数据(UPDATE 和 DELETE 可用)。它们是只读别名,不能赋值给变量再修改——必须直接赋值给 NEW.column_name。
容易踩的坑:在 BEFORE INSERT 中写 SET @tmp = NEW.id; 再 SET NEW.id = @tmp + 1; 是无效的;必须写成 SET NEW.id = NEW.id + 1;
INSERT:只有 NEW,OLD 为 NULL
DELETE:只有 OLD,NEW 为 NULL
UPDATE:NEW 和 OLD 都存在,OLD 是更新前值,NEW 是待写入值创建触发器需有 TRIGGER 权限,且不能跨库引用表(除非用 db_name.table_name 显式指定)。MySQL 8.0+ 支持多语句触发器,但必须用 BEGIN ... END 包裹,并临时修改分隔符。
DELIMITER $$ CREATE TRIGGER users_update_updated_at BEFORE UPDATE ON users FOR EACH ROW BEGIN SET NEW.updated_at = NOW(); END$$ DELIMITER ;
查看已建触发器:
SHOW TRIGGERS;
SHOW TRIGGERS LIKE 'users';
SELECT TRIGGER_NAME, ACTION_TIMING, EVENT_MANIPULATION, ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_TABLE = 'users';
性能影响容易被低估:每个触发器都会增加 DML 延迟,尤其是涉及复杂查询或跨表更新时。高并发写入场景下,应优先考虑应用层处理或异步方案。