💡 先想象两个场景:
① 学生选了一门新课,但成绩还没出。系统应该 自动把成绩设为 0(而不是 NULL)。
② 项目临时表里堆积了大量数据。希望 每周自动清空一次。
👉 这两件事都不需要"手动操作" —— 数据库可以自己干。
- 触发器(TRIGGER):当某种 数据操作 发生时自动跑(INSERT/UPDATE/DELETE)
- 事件(EVENT):当某个 时间点 到了自动跑("每周清空一次")
本章就讲这两个让数据库 "自动干活" 的工具。
一、触发器是什么?必考
1.1 一句话定义
触发器(Trigger) = 一种 "自动触发" 的存储过程。当对表执行 INSERT / UPDATE / DELETE 时,系统自动调用,无需手动 CALL。
触发器就像 "门口的红外感应灯":
① 平时不亮(不工作)
② 一旦有人进门(INSERT/UPDATE/DELETE 发生),自动亮起来(执行预设逻辑)
跟存储过程的区别在于:"存储过程要 手动 CALL,触发器是 自动跑"。
1.2 BEFORE 还是 AFTER?必考
触发器的执行时机有两种:
🛡️BEFORE 触发器
在 INSERT/UPDATE/DELETE 之前 执行。
👉 常用于:数据校验、修改新值(在数据真正写入前先处理)。
例:插入成绩为空时,先改成 0 再插入
📝AFTER 触发器
在 INSERT/UPDATE/DELETE 之后 执行。
👉 常用于:记日志、做后续操作(数据已经写好了,再做关联处理)。
例:修改专业后,记录到修改日志表
"先校验用 BEFORE,后记录用 AFTER"
1.3 触发器能干什么?了解
- ① 数据校验(如:成绩不能小于 0)
- ② 自动赋值(如:插入时空值改成默认值)
- ③ 记录日志(如:谁改了什么,什么时候改的)
- ④ 级联操作(如:删学生时同时删该学生的选课)
- ⑤ 复杂完整性约束(普通 CHECK 解决不了的)
- ⑥ 统计计算(如:插入订单时自动累加金额)
二、NEW 和 OLD(核心难点)必考核心
2.1 为什么需要 NEW 和 OLD?
触发器要操作"正在被改的那一行"。问题是:
- 怎么拿到 "新值"?(INSERT 进来的、UPDATE 后的)
- 怎么拿到 "旧值"?(UPDATE 前的、被 DELETE 的)
👉 答案:用 NEW 和 OLD 这两个 "伪记录"。
NEW = 这次操作的 "新数据"(正要插入的、修改后的)
OLD = 这次操作的 "旧数据"(修改前的、要被删除的)
用法:NEW.字段名 或 OLD.字段名,比如 NEW.score、OLD.maj。
2.2 三种操作中 NEW 和 OLD 的对应关系必考
| 操作 | NEW(新数据) | OLD(旧数据) | 说明 |
|---|---|---|---|
| INSERT | ✅ 有 | ❌ 没有 | 插入时只有新值,没有旧值 |
| UPDATE | ✅ 有 | ✅ 有 | 修改时新旧值都有 |
| DELETE | ❌ 没有 | ✅ 有 | 删除时只有旧值,没有新值 |
"插入用 NEW,删除用 OLD,修改两个都能用"
① 在 INSERT 触发器里写 OLD.字段 → 报错,没有旧数据
② 在 DELETE 触发器里写 NEW.字段 → 报错,没有新数据
三、创建触发器:完整体验实操必考
3.1 语法模板必考
CREATE TRIGGER 触发器名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON 表名
FOR EACH ROW
BEGIN
-- 触发时执行的 SQL
END
关键点:
- BEFORE / AFTER:触发时机(前/后)
- INSERT / UPDATE / DELETE:触发事件(什么操作触发)
- ON 表名:监视哪张表
- FOR EACH ROW:受影响的每一行都触发一次(必写)
触发器内部有多条以 ; 结尾的语句,跟存储过程一样要先 DELIMITER 改定界符。这是必考易错点。
3.2 例 1:BEFORE INSERT —— 自动校验必考
需求
插入成绩到 sc 表时,如果成绩为空,自动改成 0。
DELIMITER $$
CREATE TRIGGER insert_sc_trigger
BEFORE INSERT ON sc
FOR EACH ROW
BEGIN
IF NEW.score IS NULL THEN
SET NEW.score = 0;
END IF;
END $$
DELIMITER ;
-- 验证:插入一条 score 为 NULL 的记录
INSERT INTO sc VALUES ('s2', 'c8', NULL);
-- 查询结果:score 不是 NULL,而是 0
SELECT * FROM sc WHERE sno='s2' AND cno='c8';
① BEFORE INSERT ON sc:在向 sc 表插入数据 之前 触发
② NEW.score:拿到本次插入的新成绩
③ 关键:在 BEFORE 触发器里 SET NEW.score = 0,真的会改写写入数据库的值!
④ 所以 INSERT 的 NULL 最后变成了 0 存进去
3.3 例 2:AFTER UPDATE —— 自动记日志必考
需求
修改学生专业(maj 字段)时,自动把修改前后的值记录到日志表。
先建一张日志表:
CREATE TABLE update_s_log (
sno CHAR(5) NOT NULL,
sn VARCHAR(10) NOT NULL,
omaj VARCHAR(100) NOT NULL, -- 旧专业
nmaj VARCHAR(100) NOT NULL, -- 新专业
udate DATETIME NOT NULL -- 修改时间
);
然后创建触发器:
DELIMITER $$
CREATE TRIGGER update_s_trigger
AFTER UPDATE ON s
FOR EACH ROW
BEGIN
INSERT INTO update_s_log VALUES
(OLD.sno, OLD.sn, OLD.maj, NEW.maj, NOW());
END $$
DELIMITER ;
-- 验证:修改 s2 的专业
UPDATE s SET maj = '计算机' WHERE sno = 's2';
-- 查询日志:会看到一条修改记录
SELECT * FROM update_s_log;
① AFTER UPDATE:修改 之后 才记日志(数据已经改了,记录"原来是什么、现在是什么")
② OLD.maj:修改前的专业
③ NEW.maj:修改后的专业
④ 这是 UPDATE 触发器的典型用法 —— OLD 和 NEW 都用上
3.4 例 3:BEFORE DELETE —— 级联删除必考
需求
删除学生表 s 的某条记录时,自动把该学生在 sc 表中的所有选课记录也删掉。
DELIMITER $$
CREATE TRIGGER delete_s_trigger
BEFORE DELETE ON s
FOR EACH ROW
BEGIN
DELETE FROM sc WHERE sno = OLD.sno;
END $$
DELIMITER ;
-- 验证:删除学号 s1 的学生
DELETE FROM s WHERE sno = 's1';
-- s1 在 sc 表中的所有选课记录也会被自动删除
SELECT * FROM sc WHERE sno = 's1'; -- 空
① BEFORE DELETE:在删除 s 表的记录 之前,先去删 sc 表里相关的
② OLD.sno:被删学生的学号(DELETE 只有 OLD 没有 NEW)
③ 这就是"级联删除" —— 一个操作引发另一个
3.5 删除触发器
DROP TRIGGER IF EXISTS insert_sc_trigger;
① 触发器 不能用 ALTER 修改 —— 只能"先删除再重新创建"
② 删除一个表时,该表上的所有触发器 会被自动删除
四、事件:定时执行必考
4.1 事件是什么?
事件(Event) = 在指定时间点(或周期)自动执行的"任务"。也叫"临时性触发器"。
① 触发器 像"红外感应灯" —— 有人来了才亮(数据被改才触发)
② 事件 像"定时浇花器" —— 到点就工作(不管有没有事都执行)
4.2 用事件之前:开启调度器必考
事件由"事件调度器"(Event Scheduler)来管理。必须先开启它,事件才会跑。
-- 查看调度器状态
SHOW VARIABLES LIKE 'event_scheduler';
-- 开启调度器(如果是 OFF 的话)
SET GLOBAL event_scheduler = ON;
-- 关闭调度器
SET GLOBAL event_scheduler = OFF;
调度器没开,事件不会自动执行!这是初学者最容易踩的坑。
4.3 创建事件:语法必考
CREATE EVENT 事件名
ON SCHEDULE 时间调度规则
DO
-- 要执行的 SQL 语句
时间调度规则有两种
在某个时刻执行一次,执行完就完了。
AT '2024-12-31 23:59:59'
AT NOW() + INTERVAL 10 SECOND
每隔一段时间执行一次,永远循环。
EVERY 1 DAY
EVERY 5 SECOND
AT = "在某时" → 执行一次
EVERY = "每隔" → 周期执行
4.4 例 1:AT —— 一次性事件必考
需求
在 10 秒后,往 tb_one 表插入一条记录。
CREATE EVENT event_once
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 10 SECOND
DO
INSERT INTO tb_one VALUES (0, NOW());
① AT 时刻:在指定的时刻执行一次
② CURRENT_TIMESTAMP + INTERVAL 10 SECOND:当前时间 + 10 秒(即 10 秒后)
③ DO ...:要执行的 SQL(不止一条时用 BEGIN…END 包起来)
④ 10 秒后,事件自动执行,然后消失
4.5 例 2:EVERY —— 周期性事件必考
需求
每周清空一次 tb_one 表。
CREATE EVENT event_weekly_clean
ON SCHEDULE EVERY 1 WEEK
DO
DELETE FROM tb_one;
多语句的事件需要 BEGIN…END
DELIMITER $$
CREATE EVENT event_weekly_score
ON SCHEDULE EVERY 1 WEEK
DO
BEGIN
INSERT INTO week_score
SELECT sno, AVG(score), SUM(score), NOW()
FROM sc GROUP BY sno;
END $$
DELIMITER ;
这个事件每周自动跑一次,把每个学生的平均分、总分汇总到 week_score 表里。
4.6 删除事件
DROP EVENT IF EXISTS event_weekly_clean;
跟触发器不同,事件可以用 ALTER EVENT 修改(如改频率、改名字等),但本章浅讲,了解一下即可。
五、触发器 vs 事件 对比必考
5.1 核心区别必考
- 由 表的 INSERT/UPDATE/DELETE 触发
- 有 BEFORE / AFTER 之分
- 可以使用 NEW / OLD
- "有人来才亮"
- 由 时间 触发(AT 或 EVERY)
- 需要 事件调度器 开启
- 没有 NEW / OLD(不针对特定行)
- "到点就工作"
对比表
| 对比项 | 触发器 (TRIGGER) | 事件 (EVENT) |
|---|---|---|
| 触发条件 | 表的 INSERT/UPDATE/DELETE | 到达某个时间点 |
| 关键字 | BEFORE / AFTER |
AT / EVERY |
| NEW / OLD | ✅ 可以使用 | ❌ 不能使用 |
| 修改方式 | 不能 ALTER,必须删除重建 | 可以 ALTER EVENT 修改 |
| 典型用途 | 数据校验 / 记日志 / 级联 | 定时清理 / 定时统计 / 定时备份 |
"触发器响应数据变化,事件响应时间到来"
六、本章小结
📋 三句话总结
- 触发器 = 表的"自动响应",由 INSERT/UPDATE/DELETE 触发,关键是 BEFORE/AFTER + NEW/OLD。
- 事件 = 数据库的"定时器",由时间触发,关键是 AT(一次)/EVERY(周期),必须先开调度器。
- 两者都能让数据库 "自己干活",区别在于触发条件不同。
本章必考点回顾
⭐ 期末考点
- NEW 和 OLD 在 INSERT/UPDATE/DELETE 中的对应关系
- BEFORE vs AFTER 的选择(前校验后记录)
- 写一个简单触发器(实操题)
- AT vs EVERY 的区别
- 触发器 vs 事件 的对比(简答题)
课堂综合测验
在一个 INSERT 触发器中,下列写法 错误 的是?
SET NEW.score = 0;SET OLD.score = 0;IF NEW.score IS NULL THEN ...INSERT INTO log VALUES (NEW.id, NOW());✅ 错的是:B
INSERT 触发器中没有 OLD(因为是新插入的,没有"旧值"可言)。
口诀:"插入用 NEW,删除用 OLD,修改两个都能用"
下列场景应该用 BEFORE 触发器 还是 AFTER 触发器?
"插入员工记录时,如果工资为空就改为 3000 再存入"
✅ 答案:A · BEFORE INSERT
分析:
① 要 修改新值(把 NULL 改成 3000)→ 用 BEFORE
② 插入事件 → INSERT
所以是 BEFORE INSERT。
口诀:"先校验用 BEFORE,后记录用 AFTER"。
关于事件(Event),下列说法 错误 的是?
✅ 错的是:C
事件 不能用 NEW/OLD。NEW/OLD 是触发器特有的,因为触发器关联到具体的"行"操作。
事件是"到时间就跑",并不关联任何行,所以没有 NEW/OLD 概念。
下列需求中,最适合用事件 而不是触发器实现的是?
✅ 答案:C
分析:
A、B、D 都是"由数据操作触发"(INSERT/UPDATE/DELETE 时自动跑)→ 用 触发器
C 是"到指定时间触发"(每天凌晨 2 点)→ 用 事件
口诀:"触发器响应数据变化,事件响应时间到来"