MySQL触发器的详细教学与综合分析
所有知识体系文章,GitHub已收录,欢迎老板们前来Star!
GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual
MySQL触发器
一、什么是触发器
触发器(trigger)是MySQL提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(insert,delete, update)时就会激活它执行。简单理解为:你执行一条sql语句,这条sql语句的执行会自动去触发执行其他的sql语句。
二、触发器的作用
- 可在写入数据表前,强制检验或转换数据。
- 触发器发生错误时,异动的结果会被撤销。
- 部分数据库管理系统可以针对数据定义语言(DDL)使用触发器,称为DDL触发器。
- 可依照特定的情况,替换异动的指令 (INSTEAD OF)。
三、触发器创建的四要素
- 监视地点(table)
- 监视事件(insert、update、delete)
- 触发时间(after、before)
- 触发事件(insert、update、delete)
四、触发器的使用语法
语法:
before/after: 触发器是在增删改之前执行,还是之后执行
delete/insert/update: 触发器由哪些行为触发(增、删、改)
on 表名: 触发器监视哪张表的(增、删、改)操作
触发SQL代码块: 执行触发器包含的SQL语句
1CREATE TRIGGER 触发器名
2BEFORE|AFTER DELETE|INSERT|UPDATE
3ON 表名 FOR EACH ROW
4BEGIN
5触发SQL代码块;
6END;
注意: 触发器也是存储过程程序的一种,而触发器内部的执行SQL语句是可以多行操作的,所以在MySQL的存储过程程序中,要定义结束符。
如果MySQL存储过程不了解的小伙伴,可以参考此文面向MySQL存储过程编程,文章中详细讲解了MySQL存储过程的优势和语法等等,相信你会在其中得以收获。
1# 设置MySQL执行结束标志,默认为;
2delimiter //
五、触发器的基本使用
5.1 基本使用步骤
首先,我先展示一下创建的两张表,因为创建的表很简单,这里我没有提供库表操作的SQL命令。
tb_class
employee
其次,创建了一个含有update操作的存储过程
1delimiter //
2create procedure update_emp(in i int, in p int)
3begin
4 update employee set phone = p where id = i;
5end //
再创建一个触发器
分析: 触发器名称为t1,触发时间为after,监视动作为update,监视表为employee表。汇总一起解释这个触发器就是:创建一个触发器名称为t1的触发器,触发器监视employee表执行update(更新)操作后,就开始执行触发器内部SQL语句
update tb_class set num = num + 1 where id = 1;
。简单来说就是一个监视一个表的增、删、改操作并设置操作前后时间,在设置时间的范围内对另外一个表进行其他操作。
如果你学到这里还是一知半解,后面我会讲解一个订单与库存的数据关系,到那时候你就会明白了!
1delimiter //
2# 创建触发器,触发器名称为t1
3create trigger t1
4 # 触发器执行在update操作之后
5 after update
6 # 监视employee表
7 on employee
8 for each row
9begin
10 # 触发执行的SQL语句
11 update tb_class set num = num + 1 where id = 1;
12end //
最后调用函数,并查看、分析结果
1call update_emp(2, 110);
触发器在此场景的作用分析
当employee表发生update操作时,触发器就对tb_class表中的num值做修改。
执行结果发现,我们在使用函数将employee表中id为2员工的phone修改为110后,触发器监视到employee表中发生了update更新操作,就执行了内部SQL语句,也就是将tb_class表中id为1的num值自增1。
5.2 查看和删除已有的触发器
查看已有触发器:
show triggers
删除已有触发器:
drop trigger 触发器名称
5.3 for each row
这里扩展,在oracle触发器中,触发器分为行触发器和语句触发器。也就是说,假设你监视一个修改操作,它修改了1000行代码,在Oracle中触发器会触发1000次。
在oracle中,for each row如果不写,无论update语句一次影响了多少行,都只执行一次触发事件。
而MySQL中,不支持语句级触发器,所以在MySQL中并不需要在意。
六、订单与库存关系场景
订单与库存的关系: 用户下订单,意味着创建该商品订单,该商品订单中的商品数量为1,库存中的该商品数量-1。往往订单表和库存表中的数量是同时操作的,所以我们这里可以用触发器。
触发器应用: 关于订单表,下订单肯定是涉及到insert插入数据数量的操作。我们可以创建一个监视订单表insert操作后执行库存表数量-1的触发器来完成订单与库存表的同时修改。
创建表,并在表中添加几条数据:
1create table goods(
2 gid int,
3 name varchar(20),
4 num smallint
5);
6create table ord(
7 oid int,
8 gid int,
9 much smallint
10);
11insert into goods values(1,'cat',40);
12insert into goods values(2,'dog',63);
13insert into goods values(3,'pig',87);
创建触发器
1create trigger t1
2after
3insert
4on ord
5for each row
6begin
7 update goods set num = num - 1 where gid = 1;
8end$
该触发器意为,用户不管下什么订单,都会把商品编号为1的商品的库存减去1。
七、触发器中引用行变量
7.1 old和new对象语法
- 在触发目标上执行insert操作后会有一个新行,如果在触发事件中需要用到这个新行的变量,可以用new关键字表示
- 在触发目标上执行delete操作后会有一个旧行,如果在触发事件中需要用到这个旧行的变量,可以用old关键字表示
- 在触发目标上执行update操作后原纪录是旧行,新记录是新行,可以使用new和old关键字来分别操作
触发语句 | old | new |
---|---|---|
insert | 所有字段都为空 | 将要插入的数据 |
update | 更新以前该行的值 | 更新后的值 |
delete | 删除以前该行的值 | 所有字段都为空 |
7.2 old和new对象应用
关于old和new对象的应用,我在这里没有展开演示。只是将第八章的综合案例结合了old和new对象实现。综合案例中详细讲解了MySQL触发器的使用!
八、综合案例
8.1 创建表、插入表数据
tb_class为幼儿园班级表,其中cid为唯一主键,cname为大、中、小班班级标准,stuNo为班级标准内的学生个数。插入大、中、小班标准,初始化两名学生在大班。
tb_stu为幼儿园学生表,其中sid为唯一主键,sname为学生性名,cno为所在班级标准的外键。插入两条数据并初始化这两名学生在大班,因为我们在班级表中初始化了两名学生在大班嘛,所以要做此操作。
1create table tb_class
2(
3 cid int auto_increment
4 primary key,
5 cname varchar(32) not null,
6 stuNo int not null
7);
8
9INSERT INTO temp.tb_class (cname, stuNo) VALUES ('大班', 2)
10INSERT INTO temp.tb_class (cname, stuNo) VALUES ('中班', 0)
11INSERT INTO temp.tb_class (cname, stuNo) VALUES ('小班', 0)
12
13create table tb_stu
14(
15 sid int auto_increment
16 primary key,
17 sname varchar(32) not null,
18 cno int not null
19);
20
21INSERT INTO temp.tb_stu (sname, cno) VALUES ('Ziph', 1)
22INSERT INTO temp.tb_stu (sname, cno) VALUES ('Join', 1)
8.2 添加学生案例
在此表结构中,如果一位新同学来到学校学习,意味着某一个班级中会多出一名学生。假设Marry同学去小班学习,其表结构的变化为:tb_stu表中添加一条Marry的记录(注:cno = 3),tb_class表中小班记录的stuNo = 0修改为stuNo = 1
先创建一个添加学生的存储过程
1# 添加学生函数
2delimiter //
3# 创建存储过程,传入学生性名和班级参数
4create procedure add_stu(in in_sname varchar(32), in in_cno int)
5begin
6 # 插入记录
7 insert into tb_stu (sname, cno) values (in_sname, in_cno);
8end //
创建触发器
注意: 在更新学生数量SQL语句中,有一段cid = new.cno的SQL语句。这里我解释一下,new代表产生的新对象,将cid主键与添加Marry记录后产生的新纪录对象的cno外键关联。(因为insert后产生的是新纪录对象嘛,所以用new)
1# 触发器
2# 创建名称为t_add_stu的触发器
3create trigger t_add_stu
4 # 设置在insert操作之后触发
5 after
6 insert
7 # 监视tb_stu的insert操作
8 on tb_stu
9 for each row
10begin
11 # 更新学生数量(cid为tb_class表中主键,cno为tb_stu表中外键)
12 update tb_class set stuNo = stuNo + 1 where cid = new.cno;
13end //
声明回结束符
1delimiter ;
插入Marry学生记录到数据库表中
1call add_stu('Marry', 3);
执行结果就是当插入Marry学生记录的同时也修改了班级表中的小班学生数量。
8.3 删除学生案例
删除学生与添加学生十分相似,删除学生相当于是添加学生的逆过程。如果以为学生退学了或者读完了幼儿园离开学校了,就意味着班级中少了一位学生。假设Join同学读完了大班结束了幼儿园阶段的学习将要幼儿园去上小学,其表结构变化为:tb_stu删除Join这条记录(注:sid = 2),tb_class将修改Join所在大班班级级别的stuNo,即stuNo = stuNo - 1
先创建一个删除学生的存储过程
1# 删除学生
2delimiter //
3create procedure delete_stu(in in_sid int)
4begin
5 delete from tb_stu where sid = in_sid;
6end //
创建触发器
注意: 在更新学生数量的时候,书写了此段SQL语句cid = OLD.cno
。该语句使用old对象,意为Join学生的记录没有了,但是使用触发器同步修改tb_class表中的大班学生数量还需要用到关联Join学生所在记录的外键cno,使用old来句点出来的cno就是删除之前Join那一条学生记录的cno。(如果我们用new,该记录还存在吗?该记录的cno还存在吗?答案是都不存在了!)
1# 触发器
2# 创建触发器名称为t_delete_stu的触发器
3create trigger t_delete_stu
4 # 设置在delete操作之后触发
5 after
6 delete
7 # 监视tb_stu表的delete操作
8 on tb_stu
9 for each row
10begin
11 # 更新学生数量(cid为tb_class表中主键,cno为tb_stu表中外键)
12 update tb_class set stuNo = stuNo - 1 where cid = OLD.cno;
13end //
声明回结束符
1delimiter ;
删除Jion学生记录
1call delete_stu(2);
执行结果为Join记录在数据库的表中消失了,而大班的学生数量也减掉了1。
8.4 删除班级案例
因为我已经详细讲解了添加学生与删除学生,所以删除班级我就不再作过多的赘述了。那就直接说核心内容吧。删除一个班级级别比如:删除小班之前要把小班内的所有学生也被删除了,因为两个表是主外键关联的。如果只删除了小班,而没有删除小班内的所有学生,那么原小班内的所有学生现在属于哪个班级呢,就不知道了吧!所以要在删除小班之前删除小班内的所有学生。
1# 创建删除班级的存储过程
2delimiter //
3create procedure delete_class(in in_cid int)
4begin
5 delete from tb_class where cid = in_cid;
6end //
7
8# 创建触发器名称为t_delete_class的触发器
9create trigger t_delete_class
10 # 作用在delete操作之前
11 before
12 delete
13 # 监视tb_class表中的delete操作
14 on tb_class
15 for each row
16begin
17 # 同时删除所有该原班级cid的所有学生
18 delete from tb_stu where cno = OLD.cid;
19end //
20
21# 将结束符声明为;
22delimiter ;
23
24# 删除小班班级别
25call delete_class(3);
执行结果为既删除了小班,又删除小班内的所有学生。
8.5 触发器冲突问题
触发器冲突问题其实就是关联问题。为什么这么说呢?就说以下刚才这三个案例中出现的触发器冲突问题。
如果我们在写触发器的时候,将添加学生、删除学生和删除班级的触发器都写在一个查询模板中。你会发现当你在删除班级的时候,会报错。显示如下信息:
这是为什么呢?
仔细想想,我们将在案例中有两个是同一个表中的删除触发器。删除班级的触发器中定义的是删除班级时触发删除学生,而删除学生的触发器中定义的是班级人数减一。你发现了没,触发器被连着触发了。如下变化:
我们通过删除班级案例了解了,删除班级之前需要把班级内所有学生删除掉。正因为如此,我们在删除班级之前已经把所有学生都删除了,导致在删除学生的时候触发了班级人数减一的触发器,该触发器在执行过程中修改了已经被删除班级的学生人数。这问题就出在这里了,班级已经删除了,怎么修改一个本就没有的班级内的人数呢?对吧!
解决触发器冲突
为解决这个场景的触发器冲突问题,我们只能取舍一个触发器。于是,就通过命令删除了删除学生案例中使用的那个触发器,删除后删除班级就可以成功执行触发了!
1drop trigger t_delete_stu;
注意: 由于存在触发器冲突问题,我们在实际开发中需要认真考量定义触发器!
九、触发器性能和使用分析(必读)
各大论坛等等,相信在大家的文章中都不推荐使用触发器,而是推荐使用存储过程程序,这是为什么呢?
首先,存储过程程序分为存储过程、储存过程函数和触发器。也就是说这三种都是存储过程的使用都是存储过程的表现形式。
如果场景在数据量和并发量都很大的情况下,使用触发器、存储过程再加上几个事务等等,很容易出现死锁。而且在使用触发器的时候,也会出现冲突,出现问题时,我们需要追溯的代码就需要从一个触发器到另一个触发器……从而影响开发效率。从性能上看,触发器也是存储过程程序的一种,它也并没有展现出多少性能上的优势。由于触发器写起来比较隐蔽,容易被开发人员忽略,而且隐式调用触发器不易于排除依赖,对后期维护不是很友好!
所以在开发中,触发器是很少用到的。那为什么我还花时间大篇幅的讲解MySQL触发器呢?原因很简单,是因为需要扩展自己的知识储备。开发中的使用问题和是否被大家摒弃,不是你拒绝学习知识的理由。之所以存在就有它存在的道理,我们在学习的道路中不断扩充自己的知识储备即可。
假如有一天你的同事聊起触发器,你也能和他们聊聊你对触发器的见解是哈?如果你根据从未了解过此知识呢?那性质就不一样了,相信大家都懂吧!
MySQL触发器的详细教学与综合分析的更多相关文章
- mysql触发器的作用及语法
触发器是一种特殊的存储过程,它在插入,删除或改动特定表中的数据时触发运行,它比数据库本身标准的功能有更精细和更复杂的数据控制能力. 数据库触发器有下面的作用: 1.安全性.能够基于数据库的值使用户具有 ...
- 如何使用MySQL触发器trigger
阅读目录:触发器trigger的使用 创建触发器 单一执行语句.多执行语句 new.old详解 查看触发器 删除触发器:慎用触发器,不用就删除 Q:什么是触发器? A: 触发器是与表有关的数据库对象, ...
- 猎八哥浅谈MYSQL触发器
什么是MYSQL触发器,我们先了解一下触发的意思.触发的字面意思是指因触动而激发起某种反应. MYSQL必知必会中对触发器的解释是:MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于 B ...
- mysql触发器Before和After的区别
Before与After区别:before:(insert.update)可以对new进行修改. after不能对new进行修改. ...
- mysql触发器trigger 实例详解
mysql触发器trigger 实例详解 (转自 https://www.cnblogs.com/phpper/p/7587031.html) MySQL好像从5.0.2版本就开始支持触发器的功能 ...
- (转)MySQL触发器trigger示例详解
一.什么是触发器 触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合.触发器的这种特性可以协助应用在数据库端确保数据的完整性. 举个例子,比如你现在有两个表[用户表]和[ ...
- MySQL触发器的正确使用与案例分析
以下的文章主要向大家讲述的是MySQL触发器的实际使用详细说明与实际案例分析,同时本文也列举了一些在MySQL触发器的实际式操作中的代码,以下就是文章的详细内容介绍,望大家借鉴. 触发器案例 mysq ...
- mysql触发器使用方法具体解释
MySQL触发器语法具体解释: 触发器 trigger是一种特殊的存储过程.他在插入(inset).删除(delete)或改动(update)特定表中的数据时触发运行,它比数据本身标准的功能更精细和更 ...
- Mysql学习总结(10)——MySql触发器使用讲解
触发器(TRIGGER)是由事件来触发某个操作.这些事件包括INSERT语句.UPDATE语句和DELETE语句.当数据库系统执行这些事件时,就会激活触发器执行相应的操作.MySQL从5.0.2版本开 ...
随机推荐
- javascript 内存和连等赋值
JavaScript深入之内存空间详细图解 https://juejin.im/post/5bf4c3eff265da613356348a 理解javascript中的连续赋值 https://www ...
- php连接数据库 需要下载adodb
<?include('adodb/ADOdb.inc.php'); # 加载ADODB$conn = &ADONewConnection('odbc_mssql'); # 建立一个连结$ ...
- Puppeteer笔记(七):Puppeteer切换浏览器TAB页
一.Puppeteer切换浏览器TAB页 1.browser.pages() 二.上手实例Demo 功能测试:打开www.ly.com首页,定位搜索"苏州",获取新打开页面上的搜索 ...
- 移除项目中的UIWebView
1,AFN升级4.0 2,代码中搜索UIWebView移除相关文件 3,检查库是否使用的UIWebView 参考 https://www.jianshu.com/p/3a645500d461
- 技术大佬:我去,你竟然还不会用 this 关键字
上一篇文章写的是 Spring Boot 的入门,结果有读者留言说,Java 都还没搞完,搞什么 Spring Boot,唬得我一愣一愣的.那这篇就继续来搞 Java,推出广受好评的我去系列第四集:你 ...
- OpenResty高性能web平台
openresty高性能web平台安装使用 简介:OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用 ...
- 使用websocket开发智能聊天机器人
前面我们学习了异步web框架(sanic)和http异步调用库httpx,今天我们学习websocket技术. websocket简介 我们知道HTTP协议是:请求->响应,如果没有响应就一直等 ...
- 上位机开发之三菱FX3U以太网通信实践
上次跟大家介绍了一下上位机与三菱Q系列PLC通信的案例,大家可以通过点击这篇文章:上位机开发之三菱Q系列PLC通信实践(←戳这里) 今天以三菱FX3U PLC为例,跟大家介绍一下,如何实现上位机与其之 ...
- jchdl - GSL实例 - Shifter
https://mp.weixin.qq.com/s/ngQji-xi4FCCbL_2ihUi_A Shifter是移位节点的父类,定义了输入输出线,但是没有定义具体的移位方式,这个留给子类去实现 ...
- 【Storm】核心组件nimbus、supervisor、worker、executor、task
nimbus 是整个集群的控管核心,负责topology的提交.运行状态监控.任务重新分配等工作. zk就是一个管理者,监控者. 总体描述:nimbus下命令(分配任务),zk监督执行(心跳监控wor ...