💡 上课前先想象两个再普通不过的场景:
这两件事,都不需要谁守在电脑前手动操作 —— 数据库完全可以自己干。本章就讲实现它们的两个工具:
👉 触发器(TRIGGER)管"数据一变就反应";事件(EVENT)管"时间一到就执行"。就这么两件事。
触发器:数据的"自动反应"
先用一句话 + 一盏灯理解它
触发器是一段"挂"在表上的 SQL。当你对这张表做 INSERT / UPDATE / DELETE 时,它会被自动触发执行,不需要你手动去调用。
① 平时它不亮(不工作);
② 一旦有人走到门口(也就是表里发生了 INSERT/UPDATE/DELETE),它自动亮起来(执行预设逻辑)。
和上一章学的"存储过程"对比:存储过程要你手动 CALL 才跑;触发器是自动跑,这是它俩最大的不同。
两个时机:BEFORE 还是 AFTER?
触发器只有两种触发时机,记住它们各自擅长什么就行:
🛡️BEFORE 触发器
在数据操作 之前 执行。
擅长:先检查、先修改(趁数据还没写进去,做点处理)。
例:插入成绩为空时,先改成 0 再存。
📝AFTER 触发器
在数据操作 之后 执行。
擅长:记一笔、做后续(数据已经写好了,再去做关联的事)。
例:改完专业后,往日志表记一条。
触发器里最关键的两个词:NEW 和 OLD
触发器要操作的是"正在被改的那一行"。可问题是 —— 怎么拿到这行的新值和旧值?答案就是这两个特殊的词:
NEW = 这次操作的 新数据(正要插入的、或修改后的)。
OLD = 这次操作的 旧数据(修改前的、或将被删除的)。
用法很简单:NEW.字段名 或 OLD.字段名,比如 NEW.score、OLD.maj。
但不是任何时候都有 NEW 和 OLD。这张表是全章唯一需要稍微记一下的点:
| 操作 | NEW(新值) | OLD(旧值) | 怎么理解 |
|---|---|---|---|
| INSERT 插入 | ✅ 有 | ❌ 没有 | 新加进来的,没有"以前" |
| UPDATE 修改 | ✅ 有 | ✅ 有 | 改之前、改之后,两头都在 |
| DELETE 删除 | ❌ 没有 | ✅ 有 | 要删掉了,只剩"以前" |
OLD、或在 DELETE 里写 NEW 都会报错。看一个完整例子:自动把空成绩补成 0
需求:往成绩表 sc 插数据时,如果成绩 score 是空的,自动改成 0 再存进去。
DELIMITER $$
CREATE TRIGGER trg_fill_score
BEFORE INSERT ON sc
FOR EACH ROW
BEGIN
IF NEW.score IS NULL THEN
SET NEW.score = 0;
END IF;
END $$
DELIMITER ;
BEFORE INSERT ON sc:在往 sc 表插数据之前 触发。NEW.score:拿到这次要插入的新成绩。SET NEW.score = 0,是真的能改掉将要写进去的值的!NULL 最后变成了 0 存进库里。触发器内部有多条以 ; 结尾的语句。和存储过程一样,要先用 DELIMITER $$ 把结束符临时改成 $$,写完再 DELIMITER ; 改回来。忘了它就会报错。
再看一眼:改完专业,自动记一笔日志
需求:学生改了专业(maj 字段),自动把"改前 → 改后"记到日志表。这是 AFTER 触发器最典型的用法,也是唯一会同时用上 OLD 和 NEW 的场景。
DELIMITER $$
CREATE TRIGGER trg_log_maj
AFTER UPDATE ON s
FOR EACH ROW
BEGIN
INSERT INTO maj_log VALUES
(OLD.sno, OLD.maj, NEW.maj, NOW());
END $$
DELIMITER ;
OLD.maj 是改之前的专业,NEW.maj 是改之后的专业 —— 一句话就把变化记清楚了。触发器还能做"级联删除"—— 比如删一个学生时,用 BEFORE DELETE 配合 OLD.sno 把他的选课记录一起删掉。原理和上面一样,换个时机和操作而已。另外:触发器不能用 ALTER 改,要改只能"先 DROP 再重建"。
CREATE TRIGGER 触发器名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON 表名
FOR EACH ROW
BEGIN
-- 这里写触发时要执行的 SQL
END
事件:时间的"定时器"
先用一句话 + 一个浇花器理解它
事件是一个"到指定时间(或每隔一段时间)就自动执行"的任务。可以把它看成数据库自带的一个闹钟/定时器。
① 触发器像"红外感应灯" —— 有人来了才亮(数据被改才动)。
② 事件像"定时浇花器" —— 到点就喷水(不管有没有人,时间到了就干活)。
用事件之前:先把"调度器"打开
事件由数据库里一个叫"事件调度器"的开关统一管理。这个开关默认是关的 —— 不打开,你写的事件就只是躺着,不会真的跑。
-- 看看现在是开还是关
SHOW VARIABLES LIKE 'event_scheduler';
-- 打开它(关键一步!)
SET GLOBAL event_scheduler = ON;
event_scheduler = OFF。两种时间写法:AT(一次)和 EVERY(周期)
创建事件的模板很短,重点就是中间那行"时间怎么安排",只有两种:
CREATE EVENT 事件名
ON SCHEDULE 时间安排 ← 这里二选一:AT 或 EVERY
DO
-- 要执行的 SQL
在某个时刻执行一次,跑完就没了。
每隔一段时间执行一次,一直循环。
看一个例子:每周自动清空临时表
需求:临时表 tb_temp 容易堆垃圾数据,希望 每周自动清空一次。
CREATE EVENT evt_weekly_clean
ON SCHEDULE EVERY 1 WEEK
DO
DELETE FROM tb_temp;
EVERY 1 WEEK:每隔一周触发一次。DO 后面跟要做的事。如果不止一条 SQL,就用 BEGIN…END 包起来(这时也要配 DELIMITER)。DROP EVENT IF EXISTS evt_weekly_clean; 即可。一张图看懂:它俩到底差在哪
触发器 TRIGGER
有 BEFORE/AFTER,能用 NEW/OLD
事件 EVENT
要先开调度器,没有 NEW/OLD
| 对比项 | 触发器 TRIGGER | 事件 EVENT |
|---|---|---|
| 谁来触发 | 对表做 增 / 改 / 删 | 到了某个时间点 |
| 关键词 | BEFORE / AFTER | AT / EVERY |
| 能用 NEW/OLD 吗 | ✅ 能 | ❌ 不能 |
| 典型用途 | 校验数据 / 记日志 / 级联 | 定时清理 / 定时统计 / 定时备份 |
三句话带走这一章
- 触发器 = 数据的自动反应。表一被 增/改/删 就跑,靠 BEFORE/AFTER 选时机、靠 NEW/OLD 拿新旧值。
- 事件 = 时间的定时器。靠 AT(一次)/ EVERY(周期) 安排时间,记得先开调度器。
- 两者都让数据库"自己干活",区别只在于:一个被数据触发,一个被时间触发。