MySQL 触发器(Trigger)讲解
MySQL 触发器(Trigger)是一种与表相关联的特殊存储过程,它会在指定的数据库事件(如 INSERT
、UPDATE
、DELETE
)发生时自动执行。触发器常用于保证数据一致性、记录审计日志或实现复杂的业务逻辑。
一、触发器的核心概念
-
触发事件
INSERT
:插入数据时触发(如BEFORE INSERT
或AFTER INSERT
)UPDATE
:更新数据时触发(如BEFORE UPDATE
或AFTER UPDATE
)DELETE
:删除数据时触发(如BEFORE DELETE
或AFTER DELETE
)
-
触发时机
BEFORE
:在操作执行前触发(可修改即将写入的数据)AFTER
:在操作执行后触发(只能读取已提交的数据)
-
触发器作用对象
- 每个触发器只能关联一个表。
- 通过
NEW
和OLD
关键字访问数据:NEW.column_name
:表示新插入或更新的数据(INSERT
/UPDATE
)。OLD.column_name
:表示被更新或删除前的数据(UPDATE
/DELETE
)。
二、创建触发器的语法
DELIMITER $$
CREATE TRIGGER trigger_name
[BEFORE|AFTER] [INSERT|UPDATE|DELETE] ON table_name
FOR EACH ROW -- 行级触发器(逐行触发)
BEGIN-- 触发器逻辑(SQL语句)
END
$$
DELIMITER ;
三、示例详解
示例1:自动设置创建时间
需求:在插入数据前自动设置记录的创建时间。
DELIMITER $$
CREATE TRIGGER set_created_time
BEFORE INSERT ON users
FOR EACH ROW
BEGINSET NEW.created_at = NOW(); -- 修改插入前的数据
END
$$
DELIMITER ;
示例2:审计日志
需求:在删除数据后记录日志到另一张表。
DELIMITER $$
CREATE TRIGGER log_user_deletion
AFTER DELETE ON users
FOR EACH ROW
BEGININSERT INTO audit_log (action, user_id, deleted_time)VALUES ('DELETE', OLD.id, NOW()); -- OLD.id 是被删除行的原始值
END
$$
DELIMITER ;
示例3:数据校验
需求:禁止插入负数金额。
DELIMITER $$
CREATE TRIGGER validate_salary
BEFORE INSERT ON employees
FOR EACH ROW
BEGINIF NEW.salary < 0 THENSIGNAL SQLSTATE '45000' -- 抛出错误,阻止操作SET MESSAGE_TEXT = 'Salary cannot be negative';END IF;
END
$$
DELIMITER ;
四、触发器的管理
-
查看触发器
SHOW TRIGGERS; -- 显示所有触发器 SHOW CREATE TRIGGER trigger_name; -- 查看具体定义
-
删除触发器
DROP TRIGGER [IF EXISTS] trigger_name;
-
修改触发器
MySQL 不支持直接修改触发器,需先删除再重新创建。
五、触发器的优缺点
优点:
- 简化应用层逻辑,保证数据一致性。
- 自动执行级联操作(如更新关联表)。
缺点:
- 隐藏的业务逻辑:触发器可能使调试复杂化。
- 性能问题:频繁触发的复杂逻辑可能影响数据库性能。
- 循环触发风险:例如,表A的触发器修改表B,表B的触发器又修改表A。
六、注意事项
-
权限要求
创建触发器需要TRIGGER
权限。 -
事务中的触发器
触发器与所在事务共享上下文。如果触发器失败,整个事务会回滚。 -
避免递归触发
确保触发器不会导致无限循环(如更新同一张表)。 -
不支持 DDL
触发器内部不能执行CREATE TABLE
或ALTER TABLE
等DDL操作。
七、适用场景
- 数据校验:确保字段值符合业务规则。
- 审计追踪:记录关键数据的变更历史。
- 自动计算:如更新统计字段(订单总金额)。
- 级联操作:删除主表数据时同步删除关联的子表数据。
八、高级用法:FOR EACH ROW
与变量
触发器逐行处理数据,可以在 BEGIN...END
块中使用变量:
DELIMITER $$
CREATE TRIGGER update_inventory
AFTER INSERT ON orders
FOR EACH ROW
BEGINDECLARE product_id INT;DECLARE quantity INT;SET product_id = NEW.product_id;SET quantity = NEW.quantity;UPDATE products SET stock = stock - quantity WHERE id = product_id;
END
$$
DELIMITER ;
通过合理使用触发器,可以实现数据库层面的自动化逻辑,但需谨慎权衡其维护成本和性能影响。