Mysql触发器字段双向更新方式
作者:大鹏的世界
Mysql触发器字段双向更新
业务场景
不同的业务系统共用余额,hjmallind_user和ims_cjdc_user两个表不同的余额字段,但是共用余额值。
触发器定义
DROP TRIGGER IF EXISTS `test-up_ds_wallet`; CREATE TRIGGER `test-up_ds_wallet` AFTER UPDATE ON `ims_cjdc_user` FOR EACH ROW BEGIN DECLARE ds_money decimal(10,2); IF new.wallet <> old.wallet THEN select money into ds_money from hjmallind_user where ptuserid=new.id; #解决触发器死循环 IF ds_money <> new.wallet THEN UPDATE hjmallind_user set money=new.wallet where ptuserid=new.id; END IF ; END IF ; END; DROP TRIGGER IF EXISTS `test-up_wm_wallet`; CREATE TRIGGER `test-up_wm_wallet` AFTER UPDATE ON `hjmallind_user` FOR EACH ROW BEGIN DECLARE wm_wallet decimal(10,2); IF new.money <> old.money THEN select wallet into wm_wallet from ims_cjdc_user where id=new.ptuserid; #解决触发器死循环 IF wm_wallet <> new.money THEN UPDATE ims_cjdc_user set wallet=new.money where id=new.ptuserid; END IF ; END IF ; END;
校验代码
select id,wallet from ims_cjdc_user where id=164438; select id,ptuserid,money from hjmallind_user where ptuserid=164438; -- update hjmallind_user set money=money+50 where ptuserid=8426; update ims_cjdc_user set wallet=wallet+20.50 where id=164438; select id,wallet from ims_cjdc_user where id=164438; select id,ptuserid,money from hjmallind_user where ptuserid=164438;
对数据库触发器new和old的理解
在数据库的触发器中经常会用到更新前的值和更新后的值,所有要理解new和old的作用很重要。
当时我有个情况是这样的:
我要插入一行数据,在行要去其他表中获得一个单价,然后和这行的数据进行相乘的到总金额,将该行的金额替换成相乘的结果。
一开始我使用的after,然后对自身的值进行更改。
insert | update | delete | |
---|---|---|---|
old | null | 实际值 | 实际值 |
new | 实际值 | 实际值 | null |
在Oracle中用 :old
和 :new
表示执行前的行,和执行后的行。
在MySQL中用 old
和 new
表示执行前和执行后的数据。
问题的起源
之前对数据库的触发器是这样写的,
CREATE TRIGGER triggerName after insert ON consumeinfo FOR EACH ROW BEGIN UPDATE consumeinfo SET new.金额=0; END;
触发器创建没问题,但是插入数据出现以下错误。
[Err] 1442 - Can't update table 'consumeinfo' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
但是通过上网搜索的结果说对本表进行修改不用使用 update consumeinfo
,直接使用 SET new.金额=0
。
这个做法对的,因为这样使用new先对当前的金额改变了,然后存到数据库中的,不用使用update consumeinfo。
经过一番努力,以下是成功后的代码,贴出来看看
CREATE TRIGGER addnewReco BEFORE INSERT ON consumeinfo FOR EACH ROW BEGIN SET new.金额 = ( SELECT `单价` FROM pricenow WHERE `类型` = new.类型 ) * new.数量; END;
后来在吃饭打汤喝的时候突然想到new和old在after和before上使用情况不同。
其实还是因为new不能在after进行赋值,只能进行读取,复制要在before时赋值。
new和old的使用情况
下面具体说说old和new的使用情况。
在对new赋值的时候只能在触发器before中只用,在after中是不能使用的,比如(以下是正确的)。
CREATE TRIGGER updateprice BEFORE insert ON consumeinfo FOR EACH ROW BEGIN set new.金额=0; END;
这个说明对当前插入数据进行更新的时候使用before先更新完,然后才插入到数据库中的,在after的触发器中,new的赋值已经结束了,只能读取内容。
如果使用after不能使用new赋值,只能取值,否则会出错误,比如
CREATE TRIGGER updateprice AFTER insert ON consumeinfo FOR EACH ROW BEGIN set new.金额=0; END;
出现这样的错误:
[Err] 1362 - Updating of NEW row is not allowed in after trigger
总结
new在before触发器中赋值,取值;在after触发器中取值。
old在用于取值?因为赋值没意义?
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。