触发器是什么:数据库层的自动响应机制
触发器是 MySQL 中一种特殊的存储程序,它在特定表上发生
INSERT、
UPDATE或
DELETE操作时自动执行,无需应用层调用。它不是函数也不是存储过程,而是一段与表强绑定的、事件驱动的逻辑。
常见错误现象:执行
INSERT后发现数据“莫名”被改了,或日志表没写入——大概率是触发器在后台生效但未被察觉。 触发器必须关联到具体表,且一个表同一事件(如
BEFORE INSERT)只能有一个同类型触发器 不能显式调用,也不能传参;它的输入来自当前操作的行(
NEW/
OLD) 不支持事务控制语句(如
START TRANSACTION),但会参与外层语句的事务
BEFORE 和 AFTER 触发器的关键区别
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 和 OLD 的使用限制
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 延迟,尤其是涉及复杂查询或跨表更新时。高并发写入场景下,应优先考虑应用层处理或异步方案。
