MySQL数据库中触发器用法与避坑教学
作者:detayun
前言
很多刚接触MySQL可编程对象的同学,容易把触发器、存储过程、自定义函数弄混。存储过程需要手动CALL调用,自定义函数要在SELECT主动执行,而触发器不需要人工调用,它是依附于表的一段数据库逻辑,当表发生增删改事件时,自动触发执行。
触发器常用来做数据审计、数据校验、数据同步、默认值填充,在爬虫数据入库、业务日志记录场景非常实用。本文结合简单示例带你理解触发器的使用、分类以及避坑要点。
核心一句话:触发器是表事件驱动,在 INSERT / UPDATE / DELETE 发生前后自动执行的SQL逻辑。
一、触发器基础概念
触发时机
BEFORE:在数据写入表之前执行,多用于做数据校验、修改待插入的值AFTER:在数据写入表之后执行,多用于记录日志、同步数据到其他表
触发事件
INSERT:新增数据时触发UPDATE:更新数据时触发DELETE:删除数据时触发
新旧数据伪记录 NEW / OLD
这是触发器最关键的两个关键字:
NEW:代表将要插入/更新后的新行数据,INSERT、UPDATE可用,DELETE没有NEWOLD:代表更新前/删除前的旧行数据,UPDATE、DELETE可用,INSERT没有OLD
注意:触发器是行级触发器,每修改一行就触发一次,不是按整个SQL批量触发。
基础创建语法
DELIMITER //
CREATE TRIGGER 触发器名
[BEFORE|AFTER] [INSERT|UPDATE|DELETE]
ON 表名 FOR EACH ROW
BEGIN
-- 触发器业务逻辑
END //
DELIMITER ;
查看、删除触发器
-- 查看当前库所有触发器 SHOW TRIGGERS; -- 删除触发器 DROP TRIGGER IF EXISTS 触发器名称;
二、实战示例
我们先准备一张学生主表,再建一张审计日志表,实现:更新学生分数时,自动记录分数变更日志。
-- 学生表
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
score INT
);
-- 审计日志表,记录分数修改记录
CREATE TABLE student_log(
log_id INT PRIMARY KEY AUTO_INCREMENT,
student_id INT,
old_score INT,
new_score INT,
operate_time DATETIME
);
创建触发器:更新student表之后,自动写入日志
DELIMITER //
CREATE TRIGGER tr_student_score_update
AFTER UPDATE ON student
FOR EACH ROW
BEGIN
-- OLD是修改前数据,NEW是修改后数据
IF OLD.score <> NEW.score THEN
INSERT INTO student_log(student_id,old_score,new_score,operate_time)
VALUES(OLD.id, OLD.score, NEW.score, NOW());
END IF;
END //
DELIMITER ;
测试效果
INSERT INTO student(name,score) VALUES('张三',70);
UPDATE student SET score=85 WHERE id=1;
执行update之后,不用手动插入日志,student_log会自动新增一条变更记录。
示例2:BEFORE INSERT 插入前做数据校验
需求:插入学生分数,不能小于0,小于0强制改成0
DELIMITER //
CREATE TRIGGER tr_student_before_insert
BEFORE INSERT ON student
FOR EACH ROW
BEGIN
IF NEW.score < 0 THEN
SET NEW.score = 0;
END IF;
END //
DELIMITER ;
BEFORE触发器可以修改NEW里面字段的值,AFTER触发器不能修改NEW。
三、触发器适用场景
- 数据审计日志:记录数据新增、修改、删除历史,追踪数据变更人、变更前后内容,很适合爬虫入库数据追踪。
- 简单数据校验:插入前校验字段合法性,拦截非法数据,或者自动修正脏数据。
- 跨表数据同步:一张表新增/更新时,同步更新汇总表、统计表。
- 级联业务处理:删除主表记录时,自动清理附属关联数据(不推荐复杂级联,复杂业务优先程序层处理)。
四、触发器 与 存储过程、自定义函数对比
| 对象 | 触发方式 | 核心特点 |
|---|---|---|
| 触发器 | 表事件自动触发(INSERT/UPDATE/DELETE) | 依附表,无调用参数,用于自动联动逻辑 |
| 存储过程 | 手动 CALL 调用 | 支持复杂逻辑、事务,可多入参出参,返回结果集 |
| 自定义函数 | SELECT中手动调用 | 必须返回单个值,适合字段计算转换 |
五、触发器的坑与生产环境注意事项
隐形逻辑,难以排查:触发器代码藏在数据库内部,业务代码看不到。出问题时很容易忽略触发器,排错难度大,尽量不要写过于复杂的逻辑。
性能损耗:行级触发,批量update/insert时,每一行都会执行触发器内部SQL,大数据量会明显拖慢写入速度。爬虫大批量入库场景慎用。
不能在触发器内对同一张表做更新:AFTER触发器里,不可以更新当前触发的这张表,会触发循环递归报错。
事务影响:触发器和触发它的SQL属于同一个事务。触发器内部执行失败,会导致原本的insert/update语句整体回滚。
主从同步:触发器在主从架构下需要注意配置,容易出现主从数据不一致问题,线上主从环境谨慎使用。
六、什么时候不建议使用触发器
- 逻辑非常复杂,包含大量业务判断,建议放到应用程序代码中。
- 大批量导入、爬虫批量入库场景,写入性能要求很高。
- 业务频繁变动,触发器修改需要DDL,高并发库DDL风险高。
结尾
触发器的核心优势是自动执行,非常适合做数据审计、轻量数据校验这类固定联动逻辑。但它属于数据库的隐藏逻辑,可读性、排障成本高,生产环境尽量保持触发器逻辑简单,不要把复杂业务全部压到触发器中。能用应用代码实现的业务,优先在程序层处理。
到此这篇关于MySQL数据库中触发器用法与避坑教学的文章就介绍到这了,更多相关MySQL触发器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
