(15)mysql 中的触发器

1,836 阅读5分钟

概述

触发器,顾名思义就是当某个事情(事件)发生时候,执行某一段程序。触发器有四大要素:监视地点(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了,说明我们的触发器发挥作用了。

参考

blog.csdn.net/tonyxf121/a…
www.cnblogs.com/zzwlovegfj/…