本节要点

触发器简介
创建触发器
触发器的分类
触发器执行异常时的处理
删除触发器
触发器的优缺点

触发器简介

在上节课中,我们针对向学生表中插入数据这样一个需求,编写了存储过程sp_add_student。当我们需要向学生表中插入学生数据的时候,就可以像下面这样调用存储过程进行插入,而不是执行INSERT语句插入。

CALL sp_add_student(
    'S20170091', '杨艳', '女', '2003-04-09',
    15, 'G0206', 89.23, 'T0021’
);

如果有很多个学生的数据需要插入,那么我们就需要多次调用这个存储过程。

而且上一节课,我们也讲了,存储过程也是有一些缺点的。

那么,如果不使用存储过程,是否也有很方便的方法实现同样的业务逻辑呢?

这节课我们就来介绍一下触发器。使用起来也非常方便。

触发器,是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件(新增、修改、删除数据)时,将调用该对象,即表的操作事件触发表上的触发器的执行。

从这个描述来看,触发器并不需要像存储过程那样显式的执行,而是在当我们向表中新增、修改、删除数据时,自动触发执行的。

如果是这样的话,针对上面的需求,那我们直接向学生表中执行INSERT插入语句就可以了。至于判断老师编号是不是存在于老师表中,就可以交给存储过程去自动判断了。

创建触发器

创建触发器,使用关键字CREATE TRIGGER。比如,针对向学生表中插入数据时判断老师编号是否存在于老师表中的需求,我们可以编写下面这个触发器:

CREATE TRIGGER tri_add_student BEFORE INSERT
ON student FOR EACH ROW
BEGIN
    IF NOT EXISTS(SELECT 1 FROM teacher WHERE teacher_id = new.teacher_id) THEN
        INSERT INTO teacher(teacher_id) VALUES (new.teacher_id);
    END IF;
END;

其中,CREATE TRIGGER代表即将创建的是一个触发器。

tri_add_student表示即将创建的触发器的名称。当然,触发器的名称也是不能重复的。

BEFORE INSERT代表这个触发器在向表中插入数据前触发执行。

ON students代表这个触发器是用来监控student表的。

FOR EACH ROW代表对student表的每一行插入,都触发执行一次该触发器。

BEGIN与AND之间的一段代码,是触发器体,也就是触发器实际要执行的业务逻辑。

创建完上述触发器后,当我们执行下面SQL,向student表中插入数据时,该触发器就会自动被触发执行。

INSERT INTO student VALUES(
    'S20170092', '李文', '女', '2002-11-19',
    16, 'G0206', 55.32, 'T0022'
);

触发器的分类

触发器的分类还是比较多,而且还可以按不同的维度来划分。

比如,按事件类型分,触发器分为:insert触发器、update触发器、delete触发器。

按执行的先后分,触发器分为before触发器和after触发器。

在上面定义的触发器中,使用了new.teacher_id来代表即将插入学生表中的值。

与new对应的,还有old关键字,用来表示表中已有的数据。一般在update触发器和delete触发器中会用到。

触发器执行异常时的处理

我们向一个创建了before inert触发器的表中插入数据时,触发器会先于INSERT语句本身先执行。而当触发器执行失败时,INSERT语句也不会被正确的执行;

当表上有一个after触发器时,如果我们执行SQL失败,则after触发器也不会被触发;而如果SQL本身执行成功,但after触发器执行失败,则SQL语句的执行结果会自动回滚。

删除触发器

删除触发器,使用关键字DROP TRIGGER。比如:

DROP TRIGGER tri_add_student;

表示,删除触发器tri_add_student。

触发器的优缺点

通过上面的介绍,我们可以看到,触发器使用起来非常方便。一旦创建,就会在需要时自动触发,无需我们手工调用。

而且,它与存储过程一样,增强了SQL语言本身的功能和灵活性,且可以在存储过程中去实现一些检查、保证数据完整的功能,避免垃圾数据的产生。

当然,它也是有缺点的。这方面,与存储过程一样,都具有开发调试困难,可移植性差的缺点。

picture loss