触发器是一类特殊的事务,可以监视某种数据操作(insert,update,delete),并触发相关操作(insert,update,delete)
触发器创建之四要素:
监视地点 (table) |
监视事件 (insert,update,delete) |
触发时间 (after,before) |
触发事件 (insert,update,delete) |
举个例子,有两张表,分别是商品表goods和订单表ord
当下一个订单的时候,对应的商品要相应减少(买几个商品就少几个库存)
分析:
监视谁:ord
监视动作:insert
触发时间:after
触发事件:update
那么就来写创建触发器的语法:
delimiter $ (这是指定程序碰见$才结束,而不是以分号结束)
create trigger 触发器名称
after/before(触发时间)
insert/update/delete(监视事件)
on 表名(监视地址)
for each row
begin
sql1;
...
sqlN;
end $
---------------------
我们可以看到我们的商品表已经创建好了:
然后我们下订单:
我想买3只猫,那么我们用触发器来实现这个操作:
create trigger t2 after insert on ord for each row begin update goods set num=num-new.much where gid=new.gid; end$
我们可以看到订单表是空的,然后我们给里面插入数据:
然后我们去看看商品表里面的库存变了没:
我们可以看到猫的库存确实减少了三只
那我们想删除一个订单,退货,那么库存就应该再加回去,应该怎么做?
我们新建一个触发器,监视删除订单的操作:
create trigger t3 after delete on ord for each row begin update goods set num=num+old.much where gid=old.gid; end$
上面是原来的订单和库存,下面是我们执行删除订单后的数据,没有任何问题:
---------------------
那我们想修改订单,我们想把上面的订单买的猫数量改一下:我想买1只猫,三只猫太多了养不过来。
那我们建立一个新的触发器来监视订单的修改:
create trigger t4 before update on ord for each row begin update goods set num=num+old.much-new.much where gid=new.gid; end$
这是改订单之前我们的库存。
然后我们来改订单:
update ord set much=1 where oid=1$
我们可以看到猫的数量变成了33,这证明我们写的触发器没有问题。
---------------------------------
那么我们再思考,如果购买的数量超过库存应该怎么办?能不能预防?
假设我们有个大客户他下了一个订单想买25头猪:
我们增加一个订单:
insert into ord values(2,3,25)$
我们看到这个订单确实被增加进去了,但是库存呢?
我们看到这个猪的库存变成了-4,这种情况叫爆仓,这是不允许发生的,那么我们怎么预防它?
我们建立一个判断,如果new.much的值>num,那么我们把new.much=num
我们把原来的t2触发器删掉,新建一个t5触发器:
create trigger t5 before insert on ord for each row begin declare rnum int; select num into rnum from goods where gid=new.gid; if new.much>rnum then set new.much=rnum; end if; update goods set num=num-new.much where gid=new.gid; end$
注意一定要用before,否则会报下面的错误:
这是我们的库存,接下来我们生成一个订单,买25头猪:
我们可以看到库存已经为0;
订单表也显示只买了21头猪。
这证明我们的触发器确实发挥了作用。
然后我们看到我们的触发器语句里面有for each row,那么它是干啥的?
举个例子:
我们建立一个新表:
我们创建一个触发器:每当ord的数据被修改,我们就往tmp表插入一个5
create trigger t9 after update on ord for each row begin insert into tmp values(5); end$
我们看到我们的tmp现在是空的,我们接下来修改ord表中的值:
然后我们去看看tmp表有何变化:
我们可以看到tmp表一次被增加了两条数据。
这就是for each row的作用:它是声明 每一行受影响,触发器都触发一次,这种触发器也叫行级触发器。mysql暂时不支持语句级触发器