我是靠谱客的博主 耍酷电脑,最近开发中收集的这篇文章主要介绍MySQL高级篇---触发器应用MySQL触发器基本知识MySQL触发器真实案例,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

MySQL触发器基本知识

1、基本语法

触发器创建语法四要素:

  1. 监视地点(table)
  2. 监视事件(insert/update/delete)
  3. 触发时间(after/before)
  4. 触发事件(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
包含多条语句
  1. trigger_name:标识触发器名称,用户自行指定;
  2. trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
  3. trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
  4. tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
  5. trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。

通过上面的分析,我们可以得出来的结论如下:

我们可以创建6中类型的触发器

  1. before insert
  2. before update
  3. before delete
  4. after insert
  5. after update
  6. 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 语句。
  1. INSERT 型触发器:插入某一行时激活触发器,可能通过 INSERT、LOAD DATA、REPLACE 语句触发;
  2. UPDATE 型触发器:更改某一行时激活触发器,可能通过 UPDATE 语句触发;
  3. DELETE 型触发器:删除某一行时激活触发器,可能通过 DELETE、REPLACE 语句触发。

3、BEGIN … END 详解

语法:

BEGIN
[statement_list]
END
  1. statement_list 代表一个或多个语句的列表,列表内的每条语句都必须用分号(;)来结尾。
  2. 如果直接用(;)是会报错的,原因是,在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 会回滚事务,有:

  1. ①如果 BEFORE 触发器执行失败,SQL 无法正确执行。
  2. ②SQL 执行失败时,AFTER 型触发器不会触发。
  3. ③AFTER 类型的触发器执行失败,SQL 会回滚

MySQL触发器真实案例

1、案例一

增加操作

需求:

用户表中加入一条信息,头像表里面加一条对应的头像信息

  • 用户表数据库[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X7pl7FQU-1648277775970)(img/image-20220326134545840.png)]

  • 头像表[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbGTLCC9-1648277775971)(img/image-在这里插入图片描述
    .png)]

问题:

头像表中需要用到插入数据的uid,也就是主键

实现思路

  1. 创建一个触发器
  2. 触发事件是user表中增加一条记录就执行
  3. 触发条件,就是user表增加记录完毕后再执行
  4. 触发执行的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触发器真实案例所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部