概述
触发器,顾名思义就是当某个事情(事件)发生时候,执行某一段程序。触发器有四大要素:监视地点(table_name)
、监视事件(insert/update/delete)
、触发时间(before/after)
、触发执行程序(insert/update/delete)
语法
#创建触发器
create trigger triggerName
触发时间 监视事件 on 表名
for each row
begin
sql语句(触发事件)
end
————————————————————————————————————
#删除触发器
drop trigger [database_name.]trigger_name;
————————————————————————————————————
#查看触发器
show triggers;
- 触发器只能创建在永久表(permanent table)上。
- 同一个表 、同一个触发时间、相同的监视事件,只能定义一个触发器。
- 使用
old(更新前的行数据)
、new(更新后的行数据)
来引用触发器中变化的记录内容。 - 触发器只支持行级触发,不支持语句级触发,因此当处理大数据集的时候可能效率很低。。
- 触发执行程序不能调用将数据返回客户端的存储过程/函数,但允许存储程序通过参数(即out/inout参数)将数据返回触发执行程序。
- 触发器不能执行事务操作。
- 触发器不能保证原子性,例如在MYISAM中,当一个更新触发器在更新一个表后,触发对另外一个表的更新,若触发器失败,不会回滚第一个表的更新。InnoDB中的触发器和操作则是在一个事务中完成,是原子操作。
- after和before的区别:after是先完成数据的增删改,再触发,触发的语句晚于监视的增删改操作,无法影响前面的增删改动作;也就是说先插入订单记录,再更新商品的数量;before是先完成触发,再增删改,触发的语句先于监视的增删改,我们就有机会判断,修改即将发生的操作
作用
- 安全:可以基于数据库的值使用户具有操作数据库的某种权利。例如:可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。
- 审计:可以跟踪用户对数据库的操作。例如:审计用户操作数据库的语句。
- 实现复杂的数据完整性规则:实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。
- 实现复杂的非标准的数据库相关完整性规则:触发器可以对数据库中相关的表进行连环更新。例如:在修改或删除时级联修改或删除其它表中的与之匹配的行。
- 同步实时地复制表中的数据。
- 自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。例如,如果公司的帐号上的资金低于5万元则立即给财务人员发送警告数据。
举例
创建两张表goods(商品表)和order_t(订单表)
举例一
我要下一个3个商品1的订单,需要两步走,插入一条数据到订单表,更新商品表中的商品1的num列。
#没有使用触发器
insert order_t(gid,much) values('1',3);
update goods set num=num-3 where id=1;
现在,我先创建一个触发器
delimiter $$
create trigger test_tr1
after insert on order_t
for each row
begin
update goods set num=num-3 where id=1;
end $$
delimiter ;
创建完了以后,我只需执行一条就可以完成上面的任务。
#使用触发器
insert order_t(gid,much) values('1',3);
会发现商品1的数量变为7了,说明在我们插入一条订单的时候,触发器自动帮我们做了更新操作。
举例二
现在会有一个问题,因为我们触发器里面num和id都是写死的,所以不管我们买哪个商品,最终更新的都是商品1的数量。比如:我们往订单表再插入一条记录:insert into o(gid,much) values(2,3),执行完后会发现商品1的数量变4了,而商品2的数量没变,这样显然不是我们想要的结果。我们需要改改我们之前创建的触发器。
对于insert而言,新插入的行用new
来表示,行中的每一列的值用new.列名来表示。
改触发器
delimiter $$
create trigger test_tr1
after insert on order_t
for each row
begin
update goods set num=num-new.much where id=new.gid;
end $$
delimiter ;
再来测试一下,插入一条订单记录:
insert into o(gid,much) values(2,3)
执行完发现商品2的数量变为7了,现在就对了。
现在还存在两种情况:
举例三
当用户撤销一个订单的时候,我们这边直接删除一个订单,我们是不是需要把对应的商品数量再加回去呢?
对于delete而言:原本有一行,后来被删除,想引用被删除的这一行,用old
来表示,old.列名可以引用被删除的行的值。
delimiter $$
create trigger test_tri2
after delete on order_t
for each row
begin
update goods set num = num + old.much where id = old.gid;
end $$
delimiter ;
再执行
delete from order_t where id = 2;
会发现商品2的数量又变为10了。
举例四
当用户修改一个订单的数量时,我们触发器修改怎么写?
对于update而言:被修改的行,修改前的数据,用old来表示,old.列名引用被修改之前行中的值;修改的后的数据,用new来表示,new.列名引用被修改之后行中的值。
delimiter $$
create trigger test_trg3
after update on order_t
for each row
begin
update goods set num = num+old.much-new.much where id = old/new.gid;
end $$
delimiter ;
我们再修改插入的订单记录:
update order_t set much = 5 where id = 1;
我们变为买5个商品1,这时候再查询商品表就会发现商品1的数量只剩5了,说明我们的触发器发挥作用了。
参考
http://blog.csdn.net/tonyxf121/article/details/8255782
http://www.cnblogs.com/zzwlovegfj/archive/2012/07/04/2576989.html