MySQL的触发器原理应用,after和before的区别
文章目录
- 触发器
- 一、触发器的概述
- 二、触发器的基本操作
- 2.1 after和before
- 2.1.1 after
- delete型
- update型
- insert型
- 2.1.2 before
- insert型
- update型
- 三、练习
- 四、实验题
- 实验一
- 实验二
- 实验三
触发器
一、触发器的概述
触发器可以看作是一种特殊类型的存储过程,它与存储过程的区别在于存储过程使用时需要调用,而触发器是预先定义好的事件(如insert、delete、upodate等操作)发生时,才会被MySQL自动调用。
创建触发器时需要与数据表相关联,当表发生特定事件(如INSERT
、DELETE
、UPDATE
等操作)时,就会自动执行触发器中提前预订好的SQL代码.实现插人数据前,强制检验或转换数据等操作,或是在触发器中代码执行错误后撤销已执行成功的操作,保证数据的安全。因此,不难看出触发器在使用时的优点和缺点,具体内容如下。
(1)优点。
①触发器可以通过数据库中的相关表实现级联无痕更改操作。
②保证数据安全,进行安全校验。
(2)缺点。
①触发器的使用会影响数据库的结构,同时增加了维护的复杂程度。
②触发器的无痕操作会造成数据在程序(如PHP、Java等)层面不可控。
二、触发器的基本操作
触发器的基本操作包括创建触发器)查看触发器、触发器的触发和删除触发器。接下来对触发器的基本操作进行详细讲解。
1.创建触发器
在创建触发器时需要指定触发器的操作对象——数据表,且该数据表不能是临时表或视图。基本语法格式如下:
create trigger 触发器名字 触发时机 触发事件 on 表 for each row 触发顺序
begin操作的内容
end;
在上述的语法中,指定数据库下的触发器名称必须唯一,也就是不同数据库下可以含有名称相同的触发器。“ON 表 for each row ”指定触发器的操作对象。
从MySQL5.7开始,可以为一张表定义具有相同触发事件和触发时机的多个触发器。默认情况下,具有相同触发事件和触发时机的触发器按其创建顺序激活。
触发时机表示数据表在发生变化前后的两种状态,触发事件表示激活触发器的操作类型,触发顺序表示指定在同一个表中多个触发器的执行顺序,默认情况下按创建顺序激活。
创建触发器的选项
选项 | 可选值 | 描述 |
---|---|---|
触发时机 | before | 在表中数据发生改变前的状态 |
触发时机 | after | 在表中数据发生改变后的状态 |
触发事件 | insert | 插入操作 |
触发事件 | update | 更新操作 |
触发事件 | delete | 删除操作 |
触发顺序 | follows 其他触发器名称 | 新触发器在现有触发器之后激活 |
触发顺序 | precedes 其他触发器名称 | 新触发器在现有触发器之前激活 |
2.1 after和before
2.1.1 after
AFTER触发器可以根据所监视的事件分为三种,分别是INSERT型、UPDATE型和DELETE型,下面分别介绍。
delete型
建一个触发器t_d_s,当删除表student中某个学生的信息时,同时将grade表中与该学生有关的数据全部删除。
create trigger t_d_s after delete on student for each row
delete from grade where studentid = old.studentid;select * from student;
select * from grade where studentid = 'St0109010002';
select * from student where studentid = 'St0109010002';delete from student where studentid = 'St0109010002';
触发器不会产生new表和old表,所谓new,old只是指insert,delete,update操作执行前的所在表状态和执行后的状态
- 对insert而言,只有new合法,新插入的行用new来表示,行中每一列的值用new.列名来表示
- 对于delete而言,只有old合法,删除的行用old来表示,行中每一列的值用old.列名来表示
- 对于update而言,被修改的行,修改前的数据,用old来表示,old.列名;修改后的数据,用new来表示,new.列名
update型
创建一触发器t_u_s,实现在更新学生表的学号时,同时更新grade表中的相关记录的studentid值。
create trigger t_u_s after update on student for each row
update grade set studentid=new.studentid where studentid = old.studentid;select * from student;
select * from grade where studentid = 'St0109010003';
select * from student where studentid = 'St0109010003';update student set studentid = 'St0109010111' where studentid = 'St0109010003';
insert型
- 创建一个存储过程,根据student表中数据,一次性更新class表中每个班的人数
create procedure p_c1() #901 #输入班级号begindeclare claid char(20);#declare fs int;declare found boolean default true;#定义游标declare sum_c CURSOR for select classid from student;declare continue handler for not found set found=false;update class set studentnum=0;open sum_c;fetch sum_c into claid;while found doupdate class set studentnum=studentnum+1 where classid=claid;fetch sum_c into claid;end while;close sum_c;end;select * from student;
drop procedure p_c1;call p_c1();
- 创建一个触发器t_i_s,当student表插入新学生时,class表中该班级人数加1
create trigger t_i_s after insert on student for each row
update class set studentnum = studentnum + 1 where classid = new.classid;
select * from class;
insert into student(studentid,studentname,sex,classid) values("S001","zs","女","Cs010901")
2.1.2 before
BEFORE触发器是指触发器在所监视的触发事件执行之前激活,激活后执行的操作先于监视的事件,这样就有机会进行一些判断,或修改即将发生的操作。
BEFORE触发器也可以根据监视事件分为三种,分别是INSERT型、UPDATE型和DELETE型。
Before与After区别:
before:(insert、update)可以对new进行修改,after不能对new进行修改,三者都不能修改old数据。
insert型
给teacher表创建一个列, salary列,记录教师的工资
建一个触发器t_d_t,插入教师信息时,如果教师工资小于3000,则自动调整成3000
alter table teacher add salary int;
create trigger t_d_t before insert on teacher for each row
beginif new.salary < 3000 then set new.salary = 3000;end if;
end;select * from teacher;
desc teacher;insert into teacher(teacherid,teachername,sex,salary) values("dep01011","李峰","男",2000);
update型
给grade表建立一个学分列,并创建一个触发器,当修改grade表中数据时,如果修改后的成绩小于60分,则触发器将该成绩对应的课程学分修改为0,否则将学分改成对应课程的学分。
alter table grade add credit int;
create trigger t_g_t before update on grade for each row
begindeclare xf int;select credit into xf from course where courseid = new.courseid;if new.grade < 60 then set new.credit = 0;else set new.credit = xf;end if;
end;select * from grade;update grade set grade = 90 where studentid = 'St0109010004';
三、练习
一个班级最多只能有10个人,当往student表中增加新生信息时,班级表内学生人数会随之增加,当人数大于10人时,由于超过人数限制,会报系统错误,错误提示为“超过人数限制”,并且该触发器所有操作(包括引发触发器的操作)均不能成功。
create trigger t_insert_c1 after insert on student for each row
begin # 前面已经有t_i_s的触发器,所以此处不用再写相同语句# update class set studentnum = studentnum + 1 where classid = new.classid;# 取数据,如果学生信息人数大于10,则报错提示,不能再插入数据declare num int;select studentnum into num from class where classid = new.classid;if num = 39 thensignal SQLSTATE '45000' set MESSAGE_TEXT = "人数超出",MYSQL_ERRNO = 1333;end if;
end;drop trigger t_insert_c1;
select * from class;
select * from student;
insert into student(studentid,studentname,sex,classid) values("S005","zs","女","Cs010901");
四、实验题
实验一
- 定义一个触发器,为student表定义完整性规则“插入学生的信息时,性别只能为男或者女,如果输入除了男女之外的性别,则自动改为男”
create trigger t_student
before insert
on student
for each row
beginif new.sex not in('男','女') then set new.sex = "男";end if;
end;select * from student;
drop trigger t_student;
desc student;insert into student(studentid,studentname,sex,classid) values("S005","zs","鱼","Cs010901");
insert into student(studentid,studentname,sex,classid) values("S004","韦小宝","女","Cs010901");
实验二
(1)修改grade表,新增一个“remark”列,数据类型为char(10),给出修改的SQL语句。
(2)在学生表中增加一列sum_credit,将每个同学的获得的学分插入到同学对应的sum_credit列中。
(3)在成绩表中创建一个触发器,当对该表录入成绩信息时,如果分数小于60分,则将备注列的内容写为“NO”,如果大于60,则将该门课学分加在该名同学的sum_credit上,如果成绩大于100或者小于0分,中断触发器,提示“分数不合理”
(4)在成绩表中创建一个触发器,当对该表修改成绩信息时,如果分数本身大于60而修改后小于60分,则将备注列的内容写为“NO”,并在对应同学的sum_credit数据中减去这门课的学分,如果本身小于60而修改后大于等于60,则将该门课学分加在该名同学的sum_credit上,其他情况备注和总学分都不变,如果修改的成绩大于100或者小于0分,中断触发器,提示“分数不合理”
题目一
alter table grade add remark char(10);
alter table student add sum_credit int;create procedure sum_credit()
begin# 声明变量declare sid,cid VARCHAR(20);declare fs int;# 定义循环初始条件为truedeclare FOUND boolean default true;# 筛选出成绩大于60的declare sum_cur cursor forselect studentid,courseid,gradefrom gradewhere grade>60;# 查询不到记录时,将FOUND置falsedeclare continue handler for not found set FOUND = false;#初始的学分不能为空值,空值和任何值相加等于空值,必须初始化为0update student set sum_credit = 0;open sum_cur;fetch sum_cur into sid,cid,fs;while FOUND do# 将sum_credit值相加update student set sum_credit = sum_credit + (select creditfrom coursewhere courseid = cid)where StudentID = sid;fetch sum_cur into sid,cid,fs;end while;close sum_cur;select * from student;
end;call sum_credit();
select * from student;
drop procedure sum_credit;
题目二
create trigger t_s_gra before insert on grade for each row
beginif new.grade<0 or new.grade>100 then signal SQLSTATE '45000' set message_text = "分数不合理",MYSQL_ERRNO = 1333;elseif new.grade<60 then set new.remark = 'NO';else update student set sum_credit = sum_credit + (select credit from course where courseid = new.courseid) where studentid = new.studentid;end if;
end;insert into grade(courseid,studentid,semester,grade) values("Dp010001","St0109010002",2,150);
insert into grade(courseid,studentid,semester,grade) values("Dp010002","St0111040001",2,88);
insert into grade(courseid,studentid,semester,grade) values("Dp020001","St0210010002",2,50);select * from grade;
drop trigger t_s_gra;
题目三
create trigger t_s_gra before insert on grade for each row
beginif new.grade<0 OR new.grade>100 then signal SQLSTATE '45000' set message_text = '分数不合理',MYSQL_ERRNO = 1333;elseif new.grade<60 then set new.remark = 'NO';else update student set sum_credit = sum_credit + (select creditfrom coursewhere courseid = new.CourseID) where studentid = new.studentid;end if;
end;insert into grade(courseid,studentid,semester,grade) values("Dp010001","St0109010002",2,150);
insert into grade(courseid,studentid,semester,grade) values("Dp010001","St0109010002",2,80);
insert into grade(courseid,studentid,semester,grade) values("Dp020002","St0210010002",2,50);select * from grade;
drop trigger t_s_gra;select * from grade
where StudentID = "St0210010002"
题目四
create trigger t_s_grade before update on grade for each row
beginif new.grade<0 OR new.grade>100 then signal SQLSTATE '45000' set message_text = '分数不合理',MYSQL_ERRNO = 1333;elseif old.grade>60 and new.grade<60 then set new.remark = 'NO';update student set sum_credit = sum_credit-(select creditfrom coursewhere courseid = new.CourseID) where studentid = new.studentid;elseif old.grade<60 AND new.grade>=60 thenupdate student set sum_credit = sum_credit+(select creditfrom coursewhere courseid = new.CourseID) where studentid = new.studentid;end if;
end;select * from student;
select * from grade where StudentID = "St0210010005";
drop trigger t_s_grade;update grade set grade = 50 where StudentID = 'St0210010005' and CourseID = 'Dp030001';
update grade set grade = 90 where StudentID = 'St0210010005' and CourseID = 'Dp020002';
实验三
3.综合存储过程和触发器完成这个需求:
一个老师修改成绩时,后台调用存储过程和触发器,综合完成:
(1)在修改成绩之前,首先需要查看该同学该课程的成绩是否已经在表里存在了;
(2)如果该同学课程成绩未被录入,提示成绩未录入;
(3)如果该同学课程成绩已录入,修改分数差值不超过20分,正常修改。
(4)如果该同学课程成绩已录入,修改分数差值超过20分,则修改完成后会将这条成绩信息录入成绩复核表(包括学生号,课程号,修改前成绩,修改后成绩)。
成绩复核表自己创建。
create table grade_copy(StudentID varchar(20) primary key comment '学号',CourseID varchar(20) comment '课程号',old_grade int comment '原来的成绩',new_grade int comment '修改后的成绩'
);#创建该存储过程check_g通过输入进来的学号和课程号来输出他的分数
create procedure p_c_g(in sid varchar(20),in coid varchar(20),out fs int)
beginselect grade into fsfrom gradewhere StudentID = sidand courseid = coid;
end;#该触发器是对分数修改之后的操作,为了验证grade表中是否有学生成绩,没有就抛异常,有就直接修改成绩
create trigger t_gg before update on grade for each row
begindeclare f_s int;#定义临时变量来存放找到的学生成绩call p_c_g(new.StudentID,new.CourseID,@oldfs);if (@oldfs is null) then signal SQLSTATE '45000' set message_text = '成绩未录入',MYSQL_ERRNO = 1334;else # 用临时变量f_s去存放new.grade# 将grade当作一个变量来使用set f_s = new.grade;# 用临时变量f_s存放成绩,将值赋给new.gradeset new.grade = f_s;end if;
end;#以下是对分数修改之后的操作,分数差值大于20分就调用存储过程,将大于20分的学生学号和课程号传给存储过程copy
create trigger modify_t after update on grade for each row
beginif ABS(new.grade-old.grade)>20then call copy(new.StudentID,new.CourseID);end if;
end;# 复制表内数据,将触发器中得到的学号和课程号来找出grade表中的新成绩,初始成绩为全局变量
create procedure copy(in sid varchar(20),in coid varchar(20))
begin# 存放新成绩declare new_grade int;select grade into new_grade from grade where StudentID = sid and CourseID = coid;insert into grade_copy values(sid,coid,@oldfs,new_grade);
end;select * from grade where CourseID = "Dp030001"select * from grade where studentid = "St0109010001"update grade set grade = 60 where studentid = "St0109010001" and courseid = "Dp020001";update grade set grade = 65 where studentid = "St0109010001" and courseid = "Dp010004";
MySQL的触发器原理应用,after和before的区别相关推荐
- 多字段mysql触发器实例_mysql触发器原理与用法实例分析
本文实例讲述了mysql触发器原理与用法.分享给大家供大家参考,具体如下: 本文内容: 什么是触发器 创建触发器 单条触发器语句 多条触发器语句 查看触发器 删除触发器 触发器的新旧记录引用 首发日期 ...
- MySQL触发器原理
什么是触发器 触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合.触发器的这种特性可以协助应用在数据库端确保数据的完整性. 举个例子,比如你现在有两个表[用户表]和[日志 ...
- MySQL基础及原理
MySQL 写在前面 一. 数据库概述 为什么要使用数据库? 为什么要使用MySQL? Oracle和MySQL对比 RDBMS与非RDBMS 关系型数据库设计规则 ORM思想 表.记录.字段 表的四 ...
- MySQL主从复制异步原理以及搭建
MySQL主从复制的原理: 1.首先,MySQL主库在事务提交时会把数据变更作为时间events记录在二进制日志文件binlog中:MySQL主库上的sync_binlog参数控制Binlog日志以什 ...
- mysql 实时聚合分析,mysql累积聚合原理与用法实例分析
本文实例讲述了mysql累积聚合原理与用法.分享给大家供大家参考,具体如下: 累积聚合为聚合从序列内第一个元素到当前元素的数据,如为每个员工返回每月开始到现在累积的订单数量和平均订单数量 行号问题有两 ...
- mysql之触发器trigger
mysql之触发器trigger 触发器(trigger):监视某种情况,并触发某种操作. 触发器创建语法四要素:1.监视地点(table) 2.监视事件(insert/update/delete) ...
- 2.6.2.MySQL主从复制的原理
MySQL主从复制的原理 MySQL复制技术介绍 主从复制是MySQL数据库的一种容灾备份方案:是mysql自带的功能,无需借助第三方工具,MySQL的主从复制并不是数据库磁盘上的文件直接拷贝,而是通 ...
- mysql暂停触发器_mysql如何临时禁用触发器
mysql如何临时禁用触发器 起因 Mysql的触发器,在触发控制上,只能按照对数据的操作方式(Insert,Update,Delete)以及操作前后(before,after)进行触发控制.但是如果 ...
- Mysql存储引擎原理
Mysql的数据是如何组织的呢? 当然是page,也就是说mysql以页为单位进行内外存交换. 一. MySQL记录存储(页为单位) 页头 记录页面的控制信息,共占56字节,包括页的左右兄弟页面指针. ...
最新文章
- php mysql 星级评分_jQuery+PHP星级评分实现方法_jquery
- docker 时间不一致,时区设置
- 错误---获取Input的值为空字符串
- Deep Residual Learning for Image Recognition(MSRA-深度残差学习)
- Linux shell 脚本中”21″的含义解释
- gitlab服务器代码存储位置,gitlab 数据目录迁移
- git管理分支某公司的流程
- iis绑定php程序应用池设定,什么是IIS应用程序池以及应用程序池详解
- r语言adf检验结果怎么看_从AR模型到VAR模型——R语言实现
- kitti数据集 Raw Data与00-10 Ground Truth的对应关系
- 标定方法——张正友标定法
- 获取level2行情接口的功能详解
- Android HOME键那些事
- 自动下载RDS MySQL备份文件
- python抓主力资金_【邢不行|量化小讲堂系列09-Python量化入门】通过逐笔数据计算主力资金流数据...
- 图片变色HSV-shader
- 我们为什么要将图片转换成PDF?
- vue环境配置问题cmd指令报错 npm ERR! code EPERMnpm ERR! syscall mkdir
- java 抽奖算法_Java抽奖算法第二例
- 配置wine,运行qq国际版