/* 触发器 tigger 引出触发器: 在进行数据库应用软件的开发的时候,我们有时候会碰到表中的某些数据改变,同事希望引起其他相关数据改变的需求,这时候就需要使用触发器。 运用触发器可以简化程序,增加程序的灵活性 触发器是什么? 触发器是一种特殊的事务,可以监视某种数据操作(增、删、改),并触发相关操作(增、删、改) 触发器应用场景: 订单产生,库存减少 客户消费,积分变化等 触发器的创建语法 四要素: 监视地点(table) 监视事件(insert、update、delete) 触发时间(after、before) 触发事件(insert、update、delete) 查看已有triggers: show triggers 删除触发器 drop tigger tiggername 触发器使用监视表改变数据: new(新行) old(旧行) */ /* 需求: 商品表:goods 订单表:ord 当下一个订单时,对应的商品要相应减少(买几个商品就少几个库存) 分析: 监视谁:ord 监视动作:insert 出发时间:after 触发事件:update */ drop table goods; drop table ord; create table goods ( gid int, name varchar(20), num smallint ); create table ord ( oid int, gid int, munch smallint ); insert into goods values (1,'cat',34),(2,'dog',65),(3,'pig',21); --现在我希望我下订单的时候猫的数量减少2只。 --第一个触发器 create trigger t1 after insert on ord for each row begin update goods set num=num-2 where gid=1; end; --买2只猫,我们发现goods表猫的数量自己减少了2个 insert into ord values (123,1,2); select * from goods; --触发器完成了我们的要求吗?我再生成一个买3只猪的订单,发现变得还是猫,还是减少两个 insert into ord values (124,3,3); select * from goods; --前面的触发器无法实现我们的要求是因为我们在 update goods set num=num-2 where gid=1; 改变是固定的 -- 可以使用参数吗?在触发器中,如果可以,应该使用什么呢? -- 被监视的语句中的数据元素可以被我们得到吗? -- 新增的列使用new得到,删除的列使用old得到 create trigger t12 after insert on ord for each row begin update goods set num=num-new.munch where gid=new.gid; end; --添加第二个触发器失败,因为不能针对同一个列,在同一个操作,同一个时刻有两个触发器,所以我们将前面的触发器删除 show triggers; drop trigger t1; --新增了得到了触发器。 --为了便于显示,我先将订单表清空 truncate ord; select * from ord; select * from goods; --现在我想要订单买2只狗 insert into ord values (123,2,2); --买一只猫 insert into ord values (124,1,1); --发现现在的触发器满足我们的需求了 --举一反山,使用old关键字触发器控制当订单表删除订单的时候,将订单中的所属动物返还 create trigger t3 after delete on ord for each row begin update goods set num=num+old.munch where gid=old.gid; end; delete from ord where oid=124; -- 发现达到我们效果了 -- 订单改变的时候goods也随之改变 create trigger t4 after update on ord for each row begin update goods set num=num+old.munch-new.munch where gid=new.gid; end; select * from ord; select * from goods; update ord set munch=17 where gid=2; --before目前似乎并没有看出与after的区别 --一个问题:如果剩余3头猪,但是客户买了十头猪会发生什么情况?能否预防 -- 发现现在dog有21头,如果我订单买32头猪,试试 insert into ord values (124,3,32); select * from goods;-- 我发现猪变成负数了,这时候,我觉得有必要在订单增加后做一些判断以及对应的操作 -- 我先将错误订单删除,退回到前面的状态 delete from ord where oid=124; --现在,我希望修改前面的t12触发器,使他达到我的要求 --先删除再添加 drop trigger t12; create trigger t2 after insert on ord for each row begin declare rnum int; select num into rnum from goods where gid=new.gid; if new.munch>rnum then set new.munch=rnum; end if; update goods set num=num-new.munch where gid=new.gid; end; --我们添加t2触发器报错。提示:updating of new rows is not allowed in after trigger -- 这是因为我们使用的是after关键字,然后在触发器使用的时候new.munch的值已经确定了并且执行了(关键是执行了),就不能更改了,所以报错。所以这里应该将after改为before create trigger t2 before insert on ord for each row begin declare rnum int; select num into rnum from goods where gid=new.gid; if new.munch>rnum then set new.munch=rnum; end if; update goods set num=num-new.munch where gid=new.gid; end; --我们再测试一下,触发器生效了,改变了订单和goods表,避免了负数 select * from ord; select * from goods; insert into ord values (124,3,32);
/* 我们建立触发器时候的for each row有什么作用呢?为什么要使用它呢? 从字面上理解,指向每一列。 其实 for each是指定触发器为行级触发器,行级触发器指的就是每一行对应的改变都会跑一次触发器。就是在一次执行多行语句的操作中会跑多次触发器 在oracle中,触发器分语句级触发器和行级触发器,如果不写for each row表示语句级触发器,只会被触发一次 */ -- 测试一下 select * from ord; --写一个表记录触发次数 create table ct(coun int); -- 改变一下那个触发条件为update的触发器 drop trigger t4; create trigger t4 after update on ord for each row begin update goods set num=num+old.munch-new.munch where gid=new.gid; insert into ct values(5); end; --我先执行一次改变,看下效果 update ord set munch=10 where gid=2; select * from ct; --插入了一次 update ord set munch=0; select * from ct; -- 检测出插入了两次 -- 实验一下语句级别触发器 ,真是不巧,mysql暂时不支持语句级别触发器 drop trigger t4; create trigger t4 after update on ord -- for each row begin update goods set num=num+old.munch-new.munch where gid=new.gid; insert into ct values(3); end;