MySQL从删库到跑路_高级(五)——触发器
作者:天山老妖s
链接:http://blog.51cto.com/9291927
一、触发器简介
1、触发器简介
触发器是和表关联的特殊的存储过程,可以再插入,删除或修改表中的数据时触发执行,比数据库本身标准的功能有更精细和更复杂的数据控制能力。
2、触发器的优点
a、安全性
可以基于数据库的值使用户具有操作数据库的某种权利。可以基于时间限制用户的操作,例如不予许下班后和节假日修改数据库数据;可以基于数据库中的数据限制用户的操作,例如不允许股票的价格的升幅一次超过10%。
b、审计
可以跟踪用户对数据库的操作。审计用户操作数据库的语句;把用户对数据库的更新写入审计表。
c、实现复杂的数据完整性规则
实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。提供可变的缺省值。
d、实现复杂的非标准的数据库相关完整性规则。
触发器可以对数据库中相关的表进行连环更新。
在修改或删除时级联修改或删除其它表中的与之匹配的行。
在修改或删除时把其它表中的与之匹配的行设成null值。
在修改或删除时把其它表中的与之匹配的行级联设成缺省值。
触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。
e、同步实时地复制表中的数据。
f、sql触发器提供了运行计划任务的另一种方法。自动计算数据值,如果数据的值达到一定的要求,则进行特定的处理。例如,如果公司的账号上的资金低于5万元则立即给财务人员发送警告数据。
3、触发器的限制
a、触发程序不能调用将数据返回客户端的存储程序,也不能使用采用call语句的动态sql语句,但是允许存储程序通过参数将数据返回触发程序,也就是存储过程或者函数通过out或者inout类型的参数将数据返回触发器是可以的,但是不能调用直接返回数据的过程。
b、不能在触发器中使用以显示或隐式方式开始或结束事务的语句,如 select trans-action,commit或rollback。
二、触发器的使用
1、创建触发器
创建触发器的语法:
create trigger trigger_name trigger_time trigger_event on tb_name for each row trigger_stmt
trigger_name:触发器的名称。
trigger_time:触发时机,为befire或者after。
trigger_event:触发事件,为insert、delete或者update。
tb_name:表示建立触发器的表名,在哪张表上建立触发器。
trigger_stmt:触发器的程序体,可以是一条sql语句或者是用begin和end包含的多条语句。
for each row 表示任何一条记录上的操作满足触发事件都会触发该触发器。
mysql除了对insert、update、delete基本操作进行定义外,还定义了load data和replace语句,这两种语句也能引起上述6种类型的触发器的触发。
load data 语句用于将一个文件装入到一个数据表中,想当于一系列的insert操作。
replace语句一般来说和insert语句很像,只是在表中有primary key 或 unique 索引一致时,会先删除原来的数据,然后增加一条新数据。
insert型触发器:插入某一行时激活触发器,通过insert、load data、replace语句触发;
update型触发器:更改某一行时激活触发器,通过update语句触发;
delete型触发器:删除某一行时激活触发器,通过delete、replace语句触发。
变量声明:
declare var_name[,...] type [default value]
对变量赋值采用set语句,语法为:
set var_name = expr [,var_name = expr] ...
mysql中定义了new和old,用来表示触发器的所在表中,触发了触发器的哪一行数据。
在insert型触发器中,new用来表示将要(before)或已经(after)插入的新数据;
在update型触发器中,old用来表示将要或已经被修改的原数据,new用来表示将要或已经修改为的新数据;
在delete型触发器中,old用来表示将要或已经被删除的原数据;
使用方法:new.columnname(columnname为相应数据表某一列名)
另外,old是只读的,而new则可以在触发器中使用set赋值,不会再次触发触发器,造成循环调用。
2、删除触发器
drop trigger [if exists] [schema_name.] trigger_name
schema_name是数据库的名称,是可选的。如果省略了schema,将从当前数据库中舍弃触发程序。trigger_name是要删除的触发器的名称。
3、触发器信息查看
在mysql中,所有的触发器的定义都存在于information_schema数据库的triggers表中,可以通过查询命令select来查看,具体语法如下:
show triggers [from schema_name];
触发器的执行顺序
innodb数据库,若sql语句或触发器执行失败,mysql会回滚事务,有:
a、如果before触发器执行失败,sql无法正确执行。
b、sql执行失败时,after型触发器不会触发。
c、after类型的触发器执行失败,sql会回滚。
mysql的触发器是按照before触发器、行操作、after触发器的顺序执行的,其中任何一步发生错误都不会继续执行剩下的操作,如果对事务表进行的操作,如果出现错误,那么将会被回滚,数据可能会出错。
三、触发器应用
1、实现业务逻辑
客户下订单订购商品,商品表自动减少数量。
在商品表创建删除触发器,删除某商品,自动删除该商品的订单。创建产品表,有产品编号,产品名称、产品数量和产品价格四列,其中产品编号自增长列,并且设置成主键。
create table product ( pid int primary key auto_increment, pname varchar(10), price double, pnum int)engine=innodb default charset=utf8;
创建订单表,有三列,订单编号、产品编号和数量,其中订单编号自增长列,并设置成主键。
create table orders (oid int primary key auto_increment, pid int, onum int)engine=innodb default charset=utf8;
插入三种产品,产品名称和数量以及价格。
insert into product(pname,pnum,price) values('桃子',100,2);
insert into product(pname,pnum,price) values('苹果',80,8);
insert into product(pname,pnum,price) values('香蕉',50,5);
在订单表上创建触发器,当有订单,会根据订单的产品编号和数量自动减少产品的数量。触发器中new代表一个表,存放插入的订单记录。
create trigger trigger_order after insert on orders for each row begin update product set pnum = pname-new.onum where pid = new.pid; end
插入两个订单
insert into orders(pid,onum) values(1,10); insert into orders(pid,onum) values(2,5);
查看产品表,可以看到对应的产品数量减少。操作由订单表的insert触发器完成。
在订单表上创建新的触发器,当订单定的某产品产品数量大于产品库存,禁止下订单,也就是禁止在订单表中插入记录。
一张表中只能有一个insert类型的触发器,先删除insert触发器。
drop trigger trigger_order;
mysql不能在触发器中通过回滚事务取消操作,但如果触发器的sql语句执行过程中出现错误,会自动撤销操作,曲线实现事务回滚。
create trigger trigger_order before insert on orders for each row begindeclare var int;declare mesg varchar(20); select pnum into var from product where pid=new.pid;if var<new.onum then select xxxx into mesg;else update product set pnum=pnum-new.onum where pid=new.pid; end if; end
插入订单,看看如果库存不够是否还能插入成功。
insert into orders(pid, onum) values(1,110);
2、实现安全
a、限制插入记录的日期
在订单表上创建插入触发器,周六周日不允许下订单。
create trigger trigger_limitdatebefore insert on orders for each rowbegindeclare mesg varchar(10); if dayname(now())='sunday' or dayname(now())='saturday' then select xxxxx into mesg; else set mesg='允许插入订单';end if;end
验证上面创建的触发器是否工作正常,看看当前时间是否是周六周日,向订单表插入记录,检查是否能够成功。
insert into orders(pid,onum) values(3,30)
b、限制数据更改的范围
在产品表上创建更新触发器,限制产品价格一次上调不能超过20%。
触发器设置成before update,在更改前检查价格增长幅度是否超过20%,如果超过就产生错误,取消操作。
更新操作分为两步,第一步是删除原来的记录,第二部是插入新记录。原来的记录在old表中,新记录在new表中。触发器中new.price存放的是新价格,old.price是原来的价格。
create trigger trigger_limitincreaseprice before update on product for each row begin declare mesg varchar(10);if (new.price-old.price)*100/old.price > 20 then select xxxx into mesg;else set mesg='更改成功'; end if; end
验证触发器
update product set price = 20 where pid = 1;
3、实现数据完整性
使用触发器可以限制表插入某列的数值范围。
创建一个学生表,有四列,姓名、性别、手机和邮箱。
create table personinfo ( sname varchar(5), sex char(1), phone varchar(11) )engine=innodb default charset=utf8;
a、指定性别列的取值范围
创建触发器,限制性别列,只允许输入“男”和“女”。
before insert触发器,不满足条件执行有错误sql语句,退出。
create trigger trigger_limitsexbefore insert on personinfo for each rowbegindeclare mesg varchar(10); if new.sex='男' or new.sex='女' then set mesg='更改成功'; else select xxxx into mesg;end if;end
验证触发器
insert into personinfo values('孙悟空','女','18900000000'); insert into personinfo values('唐僧','男','18900000001');
b、限制手机列的取值类型和长度
创建触发器,只允许phone列输入的手机号只能是11位数字,且第一位数字是1。
create trigger trigger_limitphone before insert on personinfo for each row begin declare mesg varchar(10);if new.phone regexp '[1][0-9]{10}' then set mesg='插入成功';else select xxxx into mesg; end if; end
验证触发器,如果手机列插入的值位数不对或者第一位不是1,插入都将失败。
insert into personinfo values('唐僧','男','28900000001');
4、使用触发器审计
使用触发器实现对personinfo表数据操作的跟踪,将跟踪事件记录到一张审计表中review。
create table review ( username varchar(20),action varchar(10), studentid char(5), sname char(10), actiontime timestamp);
a、创建触发器记录插入操作
create trigger trigger_insertbefore insert on personinfo for each rowbegininsert into review values(user(),'insert',new.sname,now());end
插入personinfo表一条记录
insert into personinfo values('孙悟空','男','13008080808');
查看review表中增加的insert记录
select * from review
b、创建触发器记录删除操作
create trigger trigger_delete after delete on personinfo for each row begin insert into review values(user(),'delete',old.sname,now()); end
从personinfo删除一条记录
delete from personinfo where sname = '孙悟空';
查看reivew表中增加的delete记录
c、创建触发器记录修改操作
create trigger trigger_updateafter update on personinfo for each rowbegininsert review values(user(),'update',new.sname,now());end
更新personinfo表中名字为'孙悟空'的phone。
update personinfo set phone = '189080808' where sname = '孙悟空';
查看reivew表中增加的update记录
喜欢的小伙伴们可以搜索我们个人的微信公众号“程序员的成长之路”点击关注或扫描下方二维码
下一篇: Photoshop合成一个抽象的泣血美女