MySQL 学习笔记 2:触发器
图源:ubiq.co
触发器,就像字面意思那样,它会在数据库某些事件发生时执行一些操作。
具体来说,触发器会在特定表的INSERT
、UPDATE
、DELETE
这些类型的 SQL 语句执行时被“触发”,并执行触发器中定义好的(一条或多条) SQL 语句。
在 MySQL 中,触发器存在一些限制,我们只能对同一张表定义最多6个触发器,分别对应6个事件:
- BEFORE INSERT
- AFTER INSERT
- BEFORE UPDATE
- AFTER UPDATE
- BEFORE DELETE
- AFTER DELETE
此外,无法在触发器中调用存储过程,也无法对临时表和视图使用存储过程。
本文使用的数据库可视化工具和测试数据同上一篇文章,不再赘述。
创建触发器
用 SQLyog 创建触发器会有类似下面这样的模版:
DELIMITER $$
CREATE
/*[DEFINER = { user | CURRENT_USER }]*/
TRIGGER `jpa`.`afterStudentAdd` BEFORE/AFTER INSERT/UPDATE/DELETE
ON `jpa`.`<Table Name>`
FOR EACH ROW BEGIN
END$$
DELIMITER ;
这里的afterStudentAdd
是我们的触发器名称,名称后需要指明执行触发器的事件,也就是前面说过的6种事件之一,这里我们要按需要修改。ON
后是触发器关联的数据库和表,这里要填写需要触发器的表名。FOR EACH ROW
说明每一条数据触发事件后都会执行触发器内的 SQL。最后,在BEGIN
和END
之间填写触发器的 SQL,如果只有一条 SQL 要执行,BEGIN
和END
可以省略。
原则上同一张表的触发器名称唯一即可,但作为良好习惯,触发器名称应该在数据库中唯一。
INSERT
下面是我编写的触发器:
DELIMITER $$
CREATE
/*[DEFINER = { user | CURRENT_USER }]*/
TRIGGER `jpa`.`afterStudentAdd` AFTER INSERT
ON `jpa`.`student`
FOR EACH ROW BEGIN
declare nowTime datetime default NOW();
INSERT INTO `jpa`.`student_add_log` (`id`, `average_score`, `level`, `name`, `time`) VALUES (NEW.id, NEW.average_score, NEW.level, NEW.name, nowTime);
END$$
DELIMITER ;
这个触发器将在INSERT
语句执行后执行,作用是将新添加的数据插入一个日志表student_add_log
,并且记录添加时间。在 INSERT 事件中,我们可以使用临时表NEW
获取新添加的数据。需要注意的是,自增主键只有在数据真正添加后(INSERT
语句执行后)才会产生,所以类似的NEW.id
只有在AFTER INSERT
事件中才能获取到,BEFORE INSERT
中是不存在的。
实际上这里的局部变量
nowTime
并不是必须的。
日志表的表结构如下:
CREATE TABLE `student_add_log` (
`id` bigint NOT NULL,
`average_score` int NOT NULL,
`level` enum('FRESH_MAN','JUNIOR',