MySQL进阶三板斧(三)看清“触发器 (Trigger)”的真实面目

本文详细解析了MySQL触发器的创建、语法、实际应用,包括级联插入和删除操作,以及触发器的注意事项和限制。通过实例展示了如何使用触发器维护数据库一致性,以及面试中可能涉及的相关知识。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 在修改或删除时把其它表中的与之匹配的行级联设成缺省值。

  • 触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。当插入一个与其主健不匹配的外部键时,这种触发器会起作用。例如,可以在books.author_code 列上生成一个插入触发器,如果新值与auths.author_code列中的某值不匹配时,插入被回退。

5. 同步实时地复制表中的数据。

6. 自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。例如,如果公司的帐号上的资金低于5万元则立即给财务人员发送警告数据。

二、触发器语法

==========

1. 创建语法四要素


  1. 监视地点(table)

  2. 监视事件(insert | update | delete)

  3. 触发时间(after | before)

  4. 触发事件(insert | update | delete)

2. 语法公式


CREATE TRIGGER <trigger_name>

BEFORE|AFTER

INSERT|UPDATE|DELETE  ON <table_name> # 表名

FOR EACH ROW  # 这句话在mysql是固定的

BEGIN

<触发的SQL语句>(调用NEW/OLD参数);

END

3. 语法参数说明


  1. CREATE TRIGGER <trigger_name>  — 触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.

  2. { BEFORE | AFTER }  — 触发器触发时间设置:可以设置为事件发生前或后(前:一般用于校验;后:一般用于关联)。

  3. { INSERT | UPDATE | DELETE }  – 设定触发事件:如执行insert、update或delete的过程时激活触发器。

  4. ON <table_name>  — 触发器是属于某一个表的: 当在这个表上执行 INSERT|UPDATE|DELETE 操作的时候就导致触发器的激活. 同时,我们不能给同一张表的“同一个事件”安排两个触发器(意味着不能同时有两个Insert触发器)。

  5. FOR EACH ROW  — 触发器的执行间隔(必有的公式内容):FOR EACH ROW子句通知触发器 每隔一行执行一次动作,而不是对整个表执行一次。

  6. <触发的SQL语句>  — 触发器包含所要触发的SQL语句:这里的语句可以是任何合法的语句, 包括复合语句,但是这里的语句受的限制和函数的一样。当然,触发SQL中可以调用“触发了( INSERT | UPDATE | DELETE )触发器的那一行数据”。

例如下方代码:

create trigger add_stu

after insert on student for each row

begin

insert into student_score ( stu_id, score, rank)

values( NEW.stuid, NEW.username);  – NEW用来表示将要(BEFORE)或已经(AFTER)插入的新数据

end;

4. NEW 与 OLD关键字详解


MySQL 中定义了 NEW 和 OLD,用来表示触发器的所在表中,触发了触发器的那一行数据,来引用触发器中发生变化的记录内容,具体地:

① 在INSERT型触发器中,NEW用来表示将要(BEFORE)或已经(AFTER)插入的新数据;

② 在UPDATE型触发器中,OLD用来表示将要或已经被修改的原数据,NEW用来表示将要或已经修改为的新数据;

③ 在DELETE型触发器中,OLD用来表示将要或已经被删除的原数据;

另外,原则上请编写简单高效的触发执行语句,以免悄无声息的浪费过多资源你还不知道!

三、实际应用

======

1. 数据准备


想我初三时常年倒数,成绩稳定,因此我拿当时几位老友排名数据来纪念一波(手动挠头)。给大家提供一个测试数据;

(沿用的前两篇“视图”、“存储过程”博文中的数据)

a.学生表

CREATE TABLE student (

ID  int NOT NULL AUTO_INCREMENT  ,

NAME  varchar(30) NOT NULL ,

SEX  char(2) NOT NULL ,

AGE  int NOT NULL ,

CLASS  varchar(10) NOT NULL ,

GRADE  varchar(20) NOT NULL ,

HOBBY  varchar(100) NULL ,

PRIMARY KEY (ID)

)

#插入数据:

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘1’, ‘陈哈哈’, ‘男’, ‘15’, ‘18班’, ‘9年级’, ‘上网’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘2’, ‘扈亚鹏’, ‘男’, ‘15’, ‘18班’, ‘9年级’, ‘美食’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘3’, ‘刘晓莉’, ‘女’, ‘14’, ‘18班’, ‘9年级’, ‘金希澈’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘4’, ‘朱志鹏’, ‘男’, ‘15’, ‘18班’, ‘9年级’, ‘睡觉’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘5’, ‘徐立楠’, ‘女’, ‘14’, ‘18班’, ‘9年级’, ‘阅读’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘6’, ‘顾昊’, ‘男’, ‘15’, ‘5班’, ‘9年级’, ‘篮球’);

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY) VALUES (‘7’, ‘陈子凝’, ‘女’, ‘15’, ‘18班’, ‘9年级’, ‘看电影’);

#插入结果:

b.成绩表

CREATE TABLE student_score (

SID int(11) NOT NULL,

S_NAME varchar(30) NOT NULL,

TOTAL_SCORE int(11) NOT NULL,

RANK int(11) NOT NULL,

PRIMARY KEY (SID)

)

#插入数据:

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘1’, ‘陈哈哈’, ‘405’, ‘1760’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘2’, ‘扈亚鹏’, ‘497’, ‘1000’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘3’, ‘刘晓莉’, ‘488’, ‘1170’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘4’, ‘朱志鹏’, ‘405’, ‘1770’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘5’, ‘徐立楠’, ‘530’, ‘701’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘6’, ‘顾昊’, ‘485’, ‘1286’);

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK) VALUES (‘7’, ‘陈子凝’, ‘704’, ‘9’);

#插入结果:

c.逃课上网表

CREATE TABLE student_go_wangba (

SID int(9) NOT NULL,

SGW_NAME varchar(30) DEFAULT NULL,

TIMES int(9) DEFAULT NULL,

PRIMARY KEY (SID)

)

#插入数据:

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘1’, ‘陈哈哈’, 15);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘2’, ‘扈亚鹏’, 1);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘3’, ‘刘晓莉’, 0);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘4’, ‘朱志鹏’, 63);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘5’, ‘徐立楠’, 0);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘6’, ‘顾昊’, 7);

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES) VALUES (‘7’, ‘陈子凝’, 0);

#插入结果:

2. 使用案例


# Insert触发器 - 级联插入

表数据:以上面的三张表为例;学生表(student)、学生成绩表(student_score)、逃课上网次数表(student_go_wangba),均已学号(stuid)为主键。

需求:

  • 需要设计一个触发器A,当增加新的学生时,需要在成绩表(student_score)中插入对应的学生信息,至于“分值、排名”字段为0即可;后面由老师打分更新。

  • 需要设计一个触发器B,当增加新的学生成绩信息时,需要在逃课上网表(student_go_wangba)中插入对应的学生信息,至于“逃课上网次数”字段为0即可;后面由教导主任“小平头”去更新。(该触发器意义在于:测试after insert链式反应是否支持)

那么,如何设计触发器A呢?

  1. 首先它是一个插入Insert触发器,是建立在表student上的;

  2. 然后是after,插入后的事件;

  3. 事件内容是插入成绩表,需要插入学生的学号和姓名,number为自增,而“分值、排名”目前不需要。

  • 注意:new表示student中新插入的值

触发器A:

– 新增触发器A,当student表插入数据时,student_score表生成初始关联数据

DROP TRIGGER IF EXISTS add_stu;

create trigger add_stu

after insert on student for each row

begin

INSERT INTO student_score (SID, S_NAME, TOTAL_SCORE, RANK)

VALUES (new.ID,new.NAME, 0, 0 );

end;

触发器B:

– 新增触发器B,当student_score表插入数据时,student_go_wangba表生成初始关联数据

DROP TRIGGER IF EXISTS add_score;

create trigger add_score

after insert on student_score for each row

begin

INSERT INTO student_go_wangba (SID, SGW_NAME, TIMES)

VALUES (new.SID,new.S_NAME, 0 );

end;

查询一下我的触发器:

show triggers \G

– "\G"是干什么用的?

– 作用:在shell中树形展示

如果在Navicat中就不用 \G,直接"show triggers;"就可以。

show triggers;

执行触发器,向student表中加入一条数据:

INSERT INTO student (ID, NAME, SEX, AGE, CLASS, GRADE, HOBBY)

VALUES (‘8’, ‘李昂’, ‘男’, ‘15’, ‘18班’, ‘9年级’, ‘看片儿’);

结果如下图所示:

同时插入三个数据,两个触发器正确执行了~

注意:创建触发器和表一样,建议增加判断:DROP TRIGGER IF EXISTS `add_stu`;

# Delete触发器 - 级联删除

表数据:以上面的三张表为例;学生表(student)、学生成绩表(student_score)、逃课上网次数表(student_go_wangba),均已学号(stuid)为主键。

需求:有些老是逃课上网的学生被开除,需要删掉所有信息,以免给学校抹黑~~~

  • 需要设计一个触发器C,当删除新的学生时,需要在成绩表(student_score)中删除对应的学生信息。

  • 需要设计一个触发器D,当删除新的学生成绩信息时,需要在逃课上网表(student_go_wangba)中删除对应的学生信息。(该触发器意义在于:测试after delete链式反应是否支持)

那么,如何设计触发器C呢?

  1. 首先它是一个插入delete触发器,是建立在表student上的;

  2. 然后是after,插入后的事件;

  3. 事件内容是关联删除成绩表数据,需要删除学生的学号即可。

  • 注意:old表示student中新删除的值

触发器C:

– 新增触发器C,当student表删除数据时,student_score表删除关联数据

DROP TRIGGER IF EXISTS del_stu;

create trigger del_stu

after delete on student for each row

begin

DELETE FROM student_score where SID = old.ID;

end;

触发器D:

– 新增触发器D,当student_score表删除数据时,student_go_wangba表删除关联数据

DROP TRIGGER IF EXISTS del_score;

create trigger del_score

after delete on student_score for each row

begin

DELETE FROM student_go_wangba  where SID = old.SID;

end;

查询一下我的触发器(show triggers \G):

执行触发器,从student表中删除一条数据:

DELETE FROM student where NAME = ‘朱志鹏’

结果如下图所示:

同时删除三个数据,触发器正确执行了。朱志鹏同学数据已经木得了~

注意:创建触发器和表一样,建议增加判断:DROP TRIGGER IF EXISTS `del_stu`;

# Update触发器 - 实时更新

跟Insert触发器、Delete触发器同理,这里不再赘述

四、触发器有哪些缺陷 @江湖中人

================

下面通过参考知乎、CSDN论坛、天涯社区,简单讲解几个内容供大家参考:

问题一: 触发器有哪些限制和注意事项

回答:

触发器会有以下两种限制:

本次面试答案,以及收集到的大厂必问面试题分享:

字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
增加判断:DROP TRIGGER IF EXISTS `del_stu`;

# Update触发器 - 实时更新

跟Insert触发器、Delete触发器同理,这里不再赘述

四、触发器有哪些缺陷 @江湖中人

================

下面通过参考知乎、CSDN论坛、天涯社区,简单讲解几个内容供大家参考:

问题一: 触发器有哪些限制和注意事项

回答:

触发器会有以下两种限制:

本次面试答案,以及收集到的大厂必问面试题分享:

[外链图片转存中…(img-vKVyC3OY-1714733621271)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值