概述
MySQL触发器基本知识
1、基本语法
触发器创建语法四要素:
- 监视地点(table)
- 监视事件(insert/update/delete)
- 触发时间(after/before)
- 触发事件(insert/update/delete)
CREATE TRIGGER trigger_name
// 触发器名称
trigger_time
// 触发时机
trigger_event ON tbl_name
// trigger_event
触发事件
tbl_name
建立触发器的表名,
就是触发器是建立在哪个表上
的!!!
FOR EACH ROW
// 作用域每一行
trigger_stmt
// 触发器运行后要执行的程序题,可
以是一局sql语句,也可以用
begin 和 end
包含多条语句
- trigger_name:标识触发器名称,用户自行指定;
- trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
- trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
- tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
- trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。
通过上面的分析,我们可以得出来的结论如下:
我们可以创建6中类型的触发器
- before insert
- before update
- before delete
- after insert
- after update
- after delete
``注意`:另外有一个限制是不能同时在一个表上建立2个相同类型的触发器,因此在一个表上最多建立6个触发器。(当然,Mysql又定义了两种,分别是LOAD DATA 和 REPLACE ,MySQL是8个触发器)
2、trigger_event 详解
MySQL 除了对 INSERT、UPDATE、DELETE 基本操作进行定义外,还定义了 LOAD DATA 和 REPLACE 语句,这两种语句也能引起上述6中类型的触发器的触发。
LOAD DATA 操作:
- LOAD DATA 语句用于将一个文件装入到一个数据表中,相当与一系列的 INSERT 操作。
REPLACE 操作
- 语句一般来说和 INSERT 语句很像,只是在表中有 primary key 或 unique 索引时,如果插入的数据和原来 primary key 或 unique 索引一致时,会先删除原来的数据,然后增加一条新数据
- 也就是说,一条 REPLACE 语句有时候等价于一条INSERT 语句,有时候等价于一条 DELETE 语句加上一条 INSERT 语句。
- INSERT 型触发器:插入某一行时激活触发器,可能通过 INSERT、LOAD DATA、REPLACE 语句触发;
- UPDATE 型触发器:更改某一行时激活触发器,可能通过 UPDATE 语句触发;
- DELETE 型触发器:删除某一行时激活触发器,可能通过 DELETE、REPLACE 语句触发。
3、BEGIN … END 详解
语法:
BEGIN [statement_list] END
- statement_list 代表一个或多个语句的列表,列表内的每条语句都必须用分号(;)来结尾。
如果直接用(;)是会报错的
,原因是,在MySQL中,分号是语句结束的标识符,遇到分号表示该段语句已经结束,MySQL可以开始执行了。因此,解释器遇到statement_list 中的分号后就开始执行,然后会报出错误,因为没有找到和 BEGIN 匹配的 END。
解决上面问题的方法:
这时就会用到 DELIMITER 命令(DELIMITER 是定界符,分隔符的意思),它是一条命令,不需要语句结束标识,语法为:
DELIMITER $ 在这之后的语句,以分号结束,解释器不会有什么反应,只有遇到了$,才认为是语句结束。注意,使用完之后,我们还应该记得把它给修改回来。
案例如下:
假设系统中有两个表:
班级表 class(班级号 classID, 班内学生数 stuCount)
学生表 student(学号 stuID, 所属班级号 classID)
要创建触发器来使班级表中的班内学生数随着学生的添加自动更新,代码如下:DELIMITER $ create trigger tri_stuInsert after insert on student for each row begin declare c int; set c = (select stuCount from class where classID=new.classID); update class set stuCount = c + 1 where classID = new.classID; end$ DELIMITER ;
4、变量详解
MySQL 中使用 DECLARE 来定义一局部变量,该变量
只能在 BEGIN … END 复合语句中使用
,并且应该定义在复合语句的开头
,也就是begin下的第一行!!!
语法如下:
DECLARE var_name[,...] type [DEFAULT value]
var_name 为变量名称,变量名不区分大小写
type 为 MySQL 支持的任何数据类型
变量初始值为 NULL,如果需要,可以使用 DEFAULT 子句提供默认值,值可以被指定为一个表达式
常用:后面的值也是可以被设计为一个表达式的返回值
SET var_name = expr [,var_name = expr] ...
案例如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7zXYNDYP-1648277775968)(img/image-
.png)]DELIMITER $ -- 创建触发器 create trigger tri_stuInsert after insert on `user` for each row # 监听user表中每次增加的数据 begin # 开始 declare c int; # 创建变量,来接收返回的值 set c = (select uid from `user` where uid=new.uid); # 查询条件 insert into user_images(path,uid)VALUES('ajisdfj',c) ; # 执行插入语句 end$ DELIMITER ;
5、NEW 与 OLD 详解
DELIMITER $
-- 创建触发器
create trigger tri_stuInsert after insert
on `user` for each row
# 监听user表中每次增加的数据
begin
# 开始
declare c int;
# 创建变量,来接收返回的值
set c = (select uid from `user` where uid=new.uid);
# 查询条件
insert into user_images(path,uid)VALUES('ajisdfj',c) ; # 执行插入语句
end$
DELIMITER ;
上述示例中使用了NEW关键字,和 MS SQL Server 中的 INSERTED 和 DELETED 类似,MySQL 中定义了 NEW 和 OLD,用来表示
触发器的所在表中,触发了触发器的那一行数据。
具体地:
- 在 INSERT 型触发器中,NEW 用来表示将要(BEFORE)或已经(AFTER)插入的新数据
- 在 UPDATE 型触发器中,OLD 用来表示将要或已经被修改的原数据,NEW 用来表示将要或已经修改为的新数据;
- 在 DELETE 型触发器中,OLD 用来表示将要或已经被删除的原数据;
使用方法: NEW.columnName (columnName 为相应数据表某一列名)- 另外,OLD 是只读的,而 NEW 则可以在触发器中使用 SET 赋值,这样不会再次触发触发器,造成循环调用(如每插入一个学生前,都在其学号前加“2013”)。
举例:
原本这个学生是一班的,修改时候成为二班,那么我们要让一班的学生总数减少1,让二班的总数增加1,此刻修改一班的信息就用old.uid ,修改二班的信息就用new.uid
6、查看触发器
和查看数据库(show databases;)查看表格(show tables;)一样,查看触发器的语法如下:
SHOW TRIGGERS [``FROM` `schema_name];
案例如下:
SHOW triggers from teachingmanagement;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X8ZHpGdR-1648277775970)(img/image-
.png)]
其中,schema_name 即 Schema 的名称,在 MySQL 中 Schema 和 Database 是一样的
说人话,就是show triggers from
数据库名字
, 不必先“USE database_name;”了。
7、删除触发器
和删除数据库、删除表格一样,删除触发器的语法如下:
DROP` `TRIGGER` `[IF EXISTS] [schema_name.]trigger_name
案例如下:
如果这个触发器已经存在,那么就先废除
DROP TRIGGER IF EXISTS '触发器名字';
DROP TRIGGER IF EXISTS triName;
8、触发器执行顺序
我们建立的数据库一般都是 InnoDB 数据库,其上建立的表是事务性表,也就是事务安全的。这时,若SQL语句或触发器执行失败,MySQL 会回滚事务,有:
- ①如果 BEFORE 触发器执行失败,SQL 无法正确执行。
- ②SQL 执行失败时,AFTER 型触发器不会触发。
- ③AFTER 类型的触发器执行失败,SQL 会回滚
MySQL触发器真实案例
1、案例一
增加操作
需求:
用户表中加入一条信息,头像表里面加一条对应的头像信息
用户表数据库[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X7pl7FQU-1648277775970)(img/image-20220326134545840.png)]
头像表[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbGTLCC9-1648277775971)(img/image-
.png)]问题:
头像表中需要用到插入数据的uid,也就是主键
实现思路
- 创建一个触发器
- 触发事件是user表中增加一条记录就执行
- 触发条件,就是user表增加记录完毕后再执行
- 触发执行的sql语句,需要先获取新插入的uid,然后再头像表中进行插入
--1、删除之前的触发器
drop trigger if EXISTS
t1;
--
-- 基本语法如下:
-- CREATE TRIGGER trigger_name
-- trigger_time
-- trigger_event ON tbl_name
-- FOR EACH ROW
-- trigger_stmt
--2、开始创建触发器
delimiter $
create trigger t1
after insert
on `user` for each row
begin
-- 定义一个变量
declare c int;
-- 执行查询语句,然后将查询到的uid赋值给变量
set c = (select uid from `user` where uid=new.uid);
-- 执行插入操作,将我们的uid,路径统一插入其中即可
insert into user_images(path,uid) VALUES('/file/orgin.png',c);
end $
delimiter;
--3、查看触发器
show triggers from teachingmanagement;
--4、 在user表中执行增加操作
insert into `user`(username,passwd,number,role_id) VALUES('城市与','12345','489','1,2,3');
查看触发器:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QkZMwl8S-1648277775972)(img/image-
.png)]
user表中执行增加操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBeOP0Gp-1648277775972)(img/image-
.png)]
全部成功!!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TaG2WXAs-1648277775973)(img/image-
.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HqWV9XMt-1648277775974)(img/image-
.png)]
坑!!1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S9DP9S3b-1648277775974)(img/image-
.png)]
我们查询出来的是uid,并且跟我们变量名重复,会查询赋值失败,然后就会导致我下面插入的时候uid一直是null
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QmWQq8HO-1648277775975)(img/image-
.png)]
上面这种就可以,因为变量名不一样了!!!
2、案例二
修改操作:
非常重要!!!需要明白一点,就是什么时候使用old.uid 什么时候使用new.uid
-- 开始修改user表中的uid信息,然后我们需要在头像表里面的路径
drop trigger if EXISTS t2;
delimiter $
create trigger t2
after update
on `user` for each row
begin
declare c int;
set c = (select uid from `user` where uid=new.uid);
--c将来要赋值给头像表中的uid,所以应该是new.uid
--这里uid=old.uid 那是因为头像表里面的uid还没有修改,仍然是之前的uid,所以我们才需要进行修改这个uid,因此这里获取到的是old.uid
update user_images set uid = c where uid = old.uid;
-- 上面的意思就是,old.uid就是我们获取之前的uid,如果我们使用new.uid 那么获取的是修改之后的uid,之所以这么设计,就是方便我们进行两张表的操作,
-- 比如原本这个学生是一班的,修改时候成为二班,那么我们要让一班的学生总数减少1,让二班的总数增加1,此刻修改一班的信息就用old.uid ,修改二班的信息就用new.uid
end $
delimiter;
show triggers from teachingmanagement;
-- 进行修改操作
update `user` set uid =148
where uid = 24;
.uid
update user_images set uid = c where uid = old.uid;
– 上面的意思就是,old.uid就是我们获取之前的uid,如果我们使用new.uid 那么获取的是修改之后的uid,之所以这么设计,就是方便我们进行两张表的操作,
– 比如原本这个学生是一班的,修改时候成为二班,那么我们要让一班的学生总数减少1,让二班的总数增加1,此刻修改一班的信息就用old.uid ,修改二班的信息就用new.uid
end $
delimiter;
show triggers from teachingmanagement;
– 进行修改操作
update user
set uid =148 where uid = 24;
-- 开始修改user表中的uid信息,然后我们需要在头像表里面的路径
drop trigger if EXISTS t2;
delimiter $
create trigger t2
after update
on `user` for each row
begin
declare c int;
set c = (select uid from `user` where uid=new.uid);
--c将来要赋值给头像表中的uid,所以应该是new.uid
--这里uid=old.uid 那是因为头像表里面的uid还没有修改,仍然是之前的uid,所以我们才需要进行修改这个uid,因此这里获取到的是old.uid
update user_images set uid = c where uid = old.uid;
--上面的意思就是,old.uid就是我们获取之前的uid,如果我们使用new.uid 那么获取的是修改之后的uid,之所以这么设计,就是方便我们进行两张表的操作,
-- 比如原本这个学生是一班的,修改时候成为二班,那么我们要让一班的学生总数减少1,让二班的总数增加1,此刻修改一班的信息就用old.uid ,修改二班的信息就用new.uid
end $
delimiter;
show triggers from teachingmanagement;
-- 进行修改操作
update `user` set uid =148
where uid = 24;
最后
以上就是耍酷电脑为你收集整理的MySQL高级篇---触发器应用MySQL触发器基本知识MySQL触发器真实案例的全部内容,希望文章能够帮你解决MySQL高级篇---触发器应用MySQL触发器基本知识MySQL触发器真实案例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复