mysqlmysql 触发器 if不知道哪儿错了

MySQL触发器 - 秦朝古月 - ITeye技术网站
博客分类:
进行数据库移植,SQL Server=&MySQL。SQL Server上有如下的Trigger
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
TRIGGER [trg_risks] ON dbo.projectrisk
FOR INSERT, UPDATE
UPDATE projectrisk
SET classification =
calc&= 9 then 3
when calc &9 and calc&=4 then 2
when calc &4 then 1
from (select inserted.id, inserted.possibility*inserted.severity
as calc from inserted) as T1
where projectrisk.id = T1.id
SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS ON
简单了解了下MySQL中,Trigger的语法。
CREATE TRIGGER &触发器名称&
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON &表名称&
FOR EACH ROW
&触发器SQL语句&
DROP TRIGGER &触发器名称&
注:创建触发器需要CREATE TRIGGER权限。(HeidiSQL中执行Trigger语句会有bug)
由于MySQL中的每个触发器只能针对一个动作,所以本次移植就需要创建两个触发器。对于发生变更的行,在触发器中可以用 NEW 来代替。
下边的触发器有什么问题吗?
delimiter &&
CREATE TRIGGER trg_risks_insert
AFTER INSERT ON `projectrisk`
FOR EACH ROW
UPDATE projectrisk SET classification = CASE
WHEN possibility*severity&=9 THEN 3
WHEN possibility*severity &9 AND possibility*severity&=4 THEN 2
WHEN possibility*severity &4 THEN 1
WHERE id = new.
CREATE TRIGGER trg_risks_update
AFTER UPDATE ON `projectrisk`
FOR EACH ROW
UPDATE projectrisk SET classification = CASE
WHEN possibility*severity&=9 THEN 3
WHEN possibility*severity &9 AND possibility*severity&=4 THEN 2
WHEN possibility*severity &4 THEN 1
WHERE id = new.
问题就是,没有考虑到触发器中的修改也会触发触发器,进入了死循环。做了如下修改后,终于OK了。
delimiter &&
CREATE TRIGGER trg_risks_insert
BEFORE INSERT ON `projectrisk`
FOR EACH ROW
SET new.classification = CASE
WHEN new.possibility*new.severity&=9 THEN 3
WHEN new.possibility*new.severity &9 AND new.possibility*new.severity&=4 THEN 2
WHEN new.possibility*new.severity &4 THEN 1
CREATE TRIGGER trg_risks_update
BEFORE UPDATE ON `projectrisk`
FOR EACH ROW
SET new.classification = CASE
WHEN new.possibility*new.severity&=9 THEN 3
WHEN new.possibility*new.severity &9 AND new.possibility*new.severity&=4 THEN 2
WHEN new.possibility*new.severity &4 THEN 1
浏览: 109653 次
来自: 上海
碰到同样问题,谢谢分享。
还有 Open3.capture 系列 和 Open3.pop ...
在eclipse中怎么配置的啊
解决了我的问题,谢谢啦~
请问一下,yum install zlib-develmysql 触发器 分号竟然报错
[问题点数:20分]
mysql 触发器 分号竟然报错
[问题点数:20分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2013年6月 其他数据库开发大版内专家分月排行榜第二2013年3月 其他数据库开发大版内专家分月排行榜第二2012年12月 其他数据库开发大版内专家分月排行榜第二2012年10月 其他数据库开发大版内专家分月排行榜第二2012年9月 其他数据库开发大版内专家分月排行榜第二2012年7月 其他数据库开发大版内专家分月排行榜第二2012年6月 其他数据库开发大版内专家分月排行榜第二2011年11月 其他数据库开发大版内专家分月排行榜第二2011年10月 其他数据库开发大版内专家分月排行榜第二2011年9月 其他数据库开发大版内专家分月排行榜第二2011年6月 其他数据库开发大版内专家分月排行榜第二2011年5月 其他数据库开发大版内专家分月排行榜第二2011年4月 其他数据库开发大版内专家分月排行榜第二2011年3月 其他数据库开发大版内专家分月排行榜第二2011年2月 其他数据库开发大版内专家分月排行榜第二2010年12月 其他数据库开发大版内专家分月排行榜第二2010年11月 其他数据库开发大版内专家分月排行榜第二2010年9月 其他数据库开发大版内专家分月排行榜第二2010年7月 其他数据库开发大版内专家分月排行榜第二2010年4月 其他数据库开发大版内专家分月排行榜第二2010年3月 其他数据库开发大版内专家分月排行榜第二2010年1月 其他数据库开发大版内专家分月排行榜第二2009年12月 其他数据库开发大版内专家分月排行榜第二2008年6月 其他数据库开发大版内专家分月排行榜第二2008年5月 其他数据库开发大版内专家分月排行榜第二2008年4月 其他数据库开发大版内专家分月排行榜第二2007年5月 其他数据库开发大版内专家分月排行榜第二2007年1月 其他数据库开发大版内专家分月排行榜第二2006年10月 其他数据库开发大版内专家分月排行榜第二2006年8月 其他数据库开发大版内专家分月排行榜第二2006年6月 其他数据库开发大版内专家分月排行榜第二2006年4月 其他数据库开发大版内专家分月排行榜第二2005年9月 其他数据库开发大版内专家分月排行榜第二
2013年12月 其他数据库开发大版内专家分月排行榜第三2013年5月 其他数据库开发大版内专家分月排行榜第三2013年4月 其他数据库开发大版内专家分月排行榜第三2013年2月 其他数据库开发大版内专家分月排行榜第三2013年1月 其他数据库开发大版内专家分月排行榜第三2012年5月 其他数据库开发大版内专家分月排行榜第三2012年4月 其他数据库开发大版内专家分月排行榜第三2012年3月 其他数据库开发大版内专家分月排行榜第三2012年2月 其他数据库开发大版内专家分月排行榜第三2011年8月 其他数据库开发大版内专家分月排行榜第三2011年7月 其他数据库开发大版内专家分月排行榜第三2010年10月 其他数据库开发大版内专家分月排行榜第三2010年5月 其他数据库开发大版内专家分月排行榜第三2010年2月 其他数据库开发大版内专家分月排行榜第三2009年11月 其他数据库开发大版内专家分月排行榜第三2009年10月 其他数据库开发大版内专家分月排行榜第三2009年5月 其他数据库开发大版内专家分月排行榜第三2009年4月 其他数据库开发大版内专家分月排行榜第三2008年12月 其他数据库开发大版内专家分月排行榜第三2008年11月 其他数据库开发大版内专家分月排行榜第三2008年10月 其他数据库开发大版内专家分月排行榜第三2008年9月 其他数据库开发大版内专家分月排行榜第三2007年9月 其他数据库开发大版内专家分月排行榜第三2007年8月 其他数据库开发大版内专家分月排行榜第三2007年4月 其他数据库开发大版内专家分月排行榜第三2007年3月 其他数据库开发大版内专家分月排行榜第三2007年2月 其他数据库开发大版内专家分月排行榜第三2006年7月 其他数据库开发大版内专家分月排行榜第三2006年2月 其他数据库开发大版内专家分月排行榜第三2006年1月 其他数据库开发大版内专家分月排行榜第三2005年11月 其他数据库开发大版内专家分月排行榜第三2005年10月 其他数据库开发大版内专家分月排行榜第三
2010年 总版技术专家分年内排行榜第二
2009年 总版技术专家分年内排行榜第三
2010年 总版技术专家分年内排行榜第二
2009年 总版技术专家分年内排行榜第三
2010年 总版技术专家分年内排行榜第二
2009年 总版技术专家分年内排行榜第三
本帖子已过去太久远了,不再提供回复功能。1&& 引言[喝小酒的网摘]http://blog./a/7698.htm
Mysql的触发器和存储过程一样,都是嵌入到mysql的一段程序。触发器是mysql5新增的功能,目前线上凤巢系统、北斗系统以及哥伦布系统使用的数据库均是mysql5.0.45版本,很多程序比如fc-star管理端,sfrd(das),dorado都会用到触发器程序,实现对于数据库增、删、改引起事件的关联操作。本文介绍了触发器的类型和基本使用方法,讲述了触发器使用中容易产生的误区,从mysql源码中得到触发器执行顺序的结论,本文最后是实战遭遇的触发器经典案例。没有特殊说明时,本文的实验均基于mysql5.0.45版本。
2&& Mysql触发器的类型
2.1&& Mysql触发器的基本使用
创建触发器。创建触发器语法如下:
CREATE TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt
其中trigger_name标识触发器名称,用户自行指定;
trigger_time标识触发时机,用before和after替换;
trigger_event标识触发事件,用insert,update和delete替换;
tbl_name标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt是触发器程序体;触发器程序可以使用begin和end作为开始和结束,中间包含多条语句;
下面给出sfrd一个触发器实例:
CREATE /*!50017 DEFINER = 'root'@'localhost' */ TRIGGER trig_useracct_update
AFTER UPDATE
ON SF_User.useracct FOR EACH ROW
IF OLD.ulevelid = 10101 OR OLD.ulevelid = 10104 THEN
IF NEW.ulevelid = 10101 OR NEW.ulevelid = 10104 THEN
if NEW.ustatid != OLD.ustatid OR NEW.exbudget != OLD.exbudget THEN
INSERT into FC_Output.fcevent set type = 2, tabid = 1, level = 1, userid = NEW.userid, ustatid = NEW.ustatid, exbudget = NEW.
INSERT into FC_Output.fcevent set type = 1, tabid = 1, level = 1, userid = NEW.userid, ustatid = NEW.ustatid, exbudget = NEW.
上述触发器实例使用了OLD关键字和NEW关键字。OLD和NEW可以引用触发器所在表的某一列,在上述实例中,OLD.ulevelid表示表 SF_User.useracct修改之前ulevelid列的值,NEW.ulevelid表示表SF_User.useracct修改之后 ulevelid列的值。另外,如果是insert型触发器,NEW.ulevelid也表示表SF_User.useracct新增行的 ulevelid列值;如果是delete型触发器OLD.ulevelid也表示表SF_User.useracct删除行的ulevelid列原值。
另外,OLD列是只读的,NEW列则可以在触发器程序中再次赋值。
上述实例也使用了IF,THEN ,ELSE,END IF等关键字。在触发器程序体中,在beigin和end之间,可以使用顺序,判断,循环等语句,实现一般程序需要的逻辑功能。
查看触发器。查看触发器语法如下,如果知道触发器所在数据库,以及触发器名称等具体信息:
SHOW TRIGGERS from SF_User like &usermaps%&;&&&&&& //查看SF_User库上名称和usermaps%匹配的触发器
如果不了解触发器的具体的信息,或者需要查看数据库上所有触发器,如下:
SHOW TRIGGERS;&&&&&& //查看所有触发器
用上述方式查看触发器可以看到数据库的所有触发器,不过如果一个库上的触发器太多,由于会刷屏,可能没有办法查看所有触发器程序。这时,可以采用如下方式:
Mysql中有一个information_schema.TRIGGERS表,存储所有库中的所有触发器,desc information_schema. TRIGGERS,可以看到表结构:
+----------------------------+--------------+------+-----+---------+-------+
| Field&&&&&&&&&&&&&&&&&&&&& | Type&&&&&&&& | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+-------+
| TRIGGER_CATALOG&&&&&&&&&&& | varchar(512) | YES |&&&& | NULL&&& |&&&&&& |
| TRIGGER_SCHEMA&&&&&&&&&&&& | varchar(64) | NO&& |&&&& |&&&&&&&& |&&&&&& |
| TRIGGER_NAME&&&&&&&&&&&&&& | varchar(64) | NO&& |&&&& |&&&&&&&& |&&&&&& |
| EVENT_MANIPULATION&&&&&&&& | varchar(6)&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| EVENT_OBJECT_CATALOG&&&&&& | varchar(512) | YES |&&&& | NULL&&& |&&&&&& |
| EVENT_OBJECT_SCHEMA&&&&&&& | varchar(64) | NO&& |&&&& |&&&&&&&& |&&&&&& |
| EVENT_OBJECT_TABLE&&&&&&&& | varchar(64) | NO&& |&&&& |&&&&&&&& |&&&&&& |
| ACTION_ORDER&&&&&&&&&&&&&& | bigint(4)&&& | NO&& |&&&& | 0&&&&&& |&&&&&& |
| ACTION_CONDITION&&&&&&&&&& | longtext&&&& | YES |&&&& | NULL&&& |&&&&&& |
| ACTION_STATEMENT&&&&&&&&&& | longtext&&&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| ACTION_ORIENTATION&&&&&&&& | varchar(9)&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| ACTION_TIMING&&&&&&&&&&&&& | varchar(6)&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| ACTION_REFERENCE_OLD_TABLE | varchar(64) | YES |&&&& | NULL&&& |&&&&&& |
| ACTION_REFERENCE_NEW_TABLE | varchar(64) | YES |&&&& | NULL&&& |&&&&&& |
| ACTION_REFERENCE_OLD_ROW&& | varchar(3)&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| ACTION_REFERENCE_NEW_ROW&& | varchar(3)&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| CREATED&&&&&&&&&&&&&&&&&&& | datetime&&&& | YES |&&&& | NULL&&& |&&&&&& |
| SQL_MODE&&&&&&&&&&&&&&&&&& | longtext&&&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
| DEFINER&&&&&&&&&&&&&&&&&&& | longtext&&&& | NO&& |&&&& |&&&&&&&& |&&&&&& |
+----------------------------+--------------+------+-----+---------+-------+
这样,用户就可以按照自己的需要,查看触发器,比如使用如下语句查看上述触发器:
select * from information_schema. TRIGGERS where TRIGGER_NAME= 'trig_useracct_update'G;
删除触发器。删除触发器语法如下:
DROP TRIGGER [schema_name.]trigger_name
2.2&& Msyql触发器的trigger_time和trigger_event
现在,重新注意到trigger_time和trigger_event,上文说过, trigger_time可以用before和after替换,表示触发器程序的执行在sql执行的前还是后;trigger_event可以用 insert,update,delete替换,表示触发器程序在什么类型的sql下会被触发。
在一个表上最多建立6个触发器,即1)before insert型,2)before update型,3)before delete型,4)after insert型,5)after update型,6)after delete型。
触发器的一个限制是不能同时在一个表上建立2个相同类型的触发器。这个限制的一个来源是触发器程序体的&begin和end之间允许运行多个语句&(摘自mysql使用手册)。
另外还有一点需要注意,msyql除了对insert,update,delete基本操作进行定义外,还定义了load data和replace语句,而load data和replace语句也能引起上述6中类型的触发器的触发。
Load data语句用于将一个文件装入到一个数据表中,相当与一系列insert操作。replace语句一般来说和insert语句很像,只是在表中有 primary key和unique索引时,如果插入的数据和原来primary key和unique索引一致时,会先删除原来的数据,然后增加一条新数据;也就是说,一条replace sql有时候等价于一条insert sql,有时候等价于一条delete sql加上一条insert sql。即是:
?&& Insert型触发器:可能通过insert语句,load data语句,replace语句触发;
?&& Update型触发器:可能通过update语句触发;
?&& Delete型触发器:可能通过delete语句,replace语句触发;
3&& Mysql触发器的执行顺序
先抛出触发器相关的几个问题
3.1&& 如果before类型的触发器程序执行失败,sql会执行成功吗?
实验如下:
1)在FC_Word.planinfo中建立before触发器:
DELIMITER |
create trigger trigger_before_planinfo_update
before update
ON FC_Word.planinfo FOR EACH ROW
insert into FC_Output.abc (planid) values (New.planid);
2)查看:mysql& select showprob from planinfo where planid=1;
+----------+
| showprob |
+----------+
|&&&&&&& 2 |
+----------+
3)执行sql:
update planinfo set showprob=200 where planid=1;&&&&& 触发触发器程序;
4)由于不存在FC_Output.abc,before触发器执行失败,提示:
ERROR ): Table 'FC_Output.abc' doesn't exist
5)再次查看:
mysql& select showprob from planinfo where planid=1;
+----------+
| showprob |
+----------+
|&&&&&&& 2 |
+----------+
即修改sql未执行成功。即如果before触发器执行失败,sql也会执行失败。
3.2&& 如果sql执行失败,会执行after类型的触发器程序吗?
实验如下:
1)在FC_Word.planinfo中建立after触发器:
DELIMITER |
create trigger trigger_after_planinfo_update
after update
ON FC_Word.planinfo FOR EACH ROW
INSERT INTO FC_Output.fcevent set level = 2, type = 2, tabid = 5, userid = NEW.userid, planid = NEW.planid, planstat2 = NEW.planstat2, showprob = NEW.showprob, showrate = NEW.showrate, showfactor = NEW.showfactor, planmode = NEW.
2)查看触发表:
mysql& select * from FC_Output.fcevent where planid=1;
Empty set (0.00 sec)
没有planid=1的记录
3)执行sql:
mysql& update planinfo set showprob1=200 where planid=1;
4)由于不存在showprob1列,提示错误:
ERROR ): Unknown column 'showprob1' in 'field list'
5)再次查看触发表:
mysql& select * from FC_Output.fcevent where planid=1;
Empty set (0.00 sec)
触发表中没有planid=1的记录,sql在执行失败时,after型触发器不会执行。
3.3&& 如果after类型的触发器程序执行失败,sql会回滚吗?
实验如下:
1)在FC_Word.planinfo中建立after触发器:
DELIMITER |
create trigger trigger_after_planinfo_update
after update
ON FC_Word.planinfo FOR EACH ROW
insert into FC_Output.abc (planid) values (New.planid);
2)查看:mysql& select showprob from planinfo where planid=1;
+----------+
| showprob |
+----------+
|&&&&&&& 2 |
+----------+
3)执行sql:
update planinfo set showprob=200 where planid=1;触发触发器程序;
4)由于不存在FC_Output.abc,after触发器执行失败,提示:
ERROR ): Table 'FC_Output.abc' doesn't exist
5)再次查看:
mysql& select showprob from planinfo where planid=1;
+----------+
| showprob |
+----------+
|&&&&&&& 2 |
+----------+
即修改sql未执行成功。即如果after触发器执行失败,sql会回滚。
这里需要说明一下,上述实验所使用的mysql引擎是innodb,innodb引擎也是目前线上凤巢系统、北斗系统以及哥伦布系统所使用的引擎,在 innodb上所建立的表是事务性表,也就是事务安全的。&对于事务性表,如果触发程序失败(以及由此导致的整个语句的失败),该语句所执行的所有更改将回滚。对于非事务性表,不能执行这类回滚&(摘自mysql使用手册)。因而,即使语句失败,失败之前所作的任何更改依然有效,也就是说,对于 innodb引擎上的数据表,如果触发器中的sql或引发触发器的sql执行失效,则事务回滚,所有操作会失效。
3.4&& mysql触发器程序执行的顺序
当一个表既有before类型的触发器,又有after类型的触发器时;当一条sql语句涉及多个表的update时,sql、触发器的执行顺序经过mysql源码包装过,有时比较复杂。
可以先看一段mysql的源代码,当SQL中update多表的时候,Mysql的执行过程如下(省去了无关代码):
/* 遍历要更新的所有表 */
for (cur_table= update_ cur_ cur_table= cur_table-&next_local)
org_updated = updated
/* 如果有 BEFORE 触发器,则执行;如果执行失败,跳到err2位置 */
if (table-&triggers &&
table-&triggers-&process_triggers(thd, TRG_EVENT_UPDATE,TRG_ACTION_BEFORE, TRUE))
goto err2;
/*执行更新,如果更新失败,跳到err位置*/
if(local_error=table-&file-&update_row(table-&record[1], table-&record[0])))
updated++; // 更新计数器
/* 如果有 AFTER 触发器,则执行;如果执行失败,跳到err2位置*/
if (table-&triggers &&
table-&triggers-&process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))
goto err2;
/*标志错误信息,写日志等*/
/*恢复执行过的操作*/
check_opt_it.rewind();
/*如果执行了更新,且表是有事务的,做标志*/
if (updated != org_updated)
if (table-&file-&has_transactions())
transactional_tables= 1;
从上面代码可以找到本章开始时抛出问题的答案。
1)&& 如果before型触发器执行失败,直接goto跳到err2位置,不会执行后续sql语句;
2)&& 如果sql执行失败,直接goto跳到err位置,不会执行或许的after型触发器;
3)&& 如过after触发器执行失败,goto到err2位置,恢复执行过的操作,且在事务型的表上做标记。
另外,在使用复杂的sql时,由于有些复杂的sql是mysql自己定义的,所以存在不确定性,使用简单的sql比较可控。
4&& Mysql触发器在数据库同步中的表现
4.1&& 触发器运行失败时,数据库同步会失败吗?
有同步关系如下dbA?dbB。初始时同步正常。
1)在dbB上建立触发器:
DELIMITER |
create trigger trigger_after_planinfo_update
after update
ON FC_Word.planinfo FOR EACH ROW
insert into FC_Output.abc (planid) values (New.planid);
2)在dbA上执行sql,执行成功;
mysql& update planinfo set showprob=200 where planid= 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
3)由于dbB上没有FC_Output.abc表,触发器会执行失败,这时,检查一下同步状态:
Slave_IO_Running: Yes
Slave_SQL_Running: NO
Last_Errno: 1146
Last_Error: Error 'Table 'FC_Output.abc' doesn't exist' on query. Default database: 'FC_Word'. Query: 'update planinfo set showprob=200 where planid= 1'
可以看到IO线程运行正常,sql线程运行失败,并提示触发器运行失败的错误信息。
回忆一下3.1和3.3所述部分,无论是before部分的触发器还是after类型的触发器,对于innodb引擎,当触发器执行失败时,相应sql也会执行失败,所以数据库同步也会失败。
4.2&& 创建、删除触发器写bin-log
创建和删除触发器的语句也会写入bin-log里,所以也会如一般的insert,update,delete语句一样同步到下游数据库中,即上游创建触发器,下游也会创建。
这里再引出两个小问题:有同步关系dbA?dbB,
1)&& 在dbA上创建一个触发器,如果dbB上已经有同表同类型的触发器,同步状态如何?
2)&& 在dbB上删除一个触发器,如果dbB上没有对应触发器,同步状态如何?
这两个问题可以类比同步中的insert语句和delete语句,答案就是
1)&& 同步失败,因为不允许重复创建同表同类型的触发器;
2)&& 同步正常,因为drop一个不存在的触发器,不影响运行结果;
5&& Mysql触发器经典案例
5.1&& 案例1 一条sql涉及多个表的update时,触发得到update之前的旧值
【现象】表test_info上建有触发器如下:
CREATE /*!50017 DEFINER = 'root'@'localhost' */ TRIGGER trig_test_info_update
AFTER UPDATE
ON FC_Word.test_info FOR EACH ROW
DECLARE tlevel INTEGER DEFAULT 0;
DECLARE ttype INTEGER DEFAULT 0;
SET tlevel = 4;
SET ttype = 33;
INSERT INTO TEST_Output.fcevent (te, le, uid, pid, uid, wid, bi, mbid, wl) SELECT ttype, tlevel, NEW.uid, NEW.pid, NEW.uid, NEW.wid, NEW.bi, NEW.mbid, wl FROM TEST_Word.wext2 where wid = NEW.
/*。。。其余部分逻辑省略*/
这个触发器程序有点长,可以单看飘黄的两句,即更新操作满足第一个条件执行飘黄语句时,触发器的行为。触发器是建立在test_info表上的,飘黄语句中可以看到,也需要查询wext2表。
执行如下sql1:
Update test_info a, wext2 b set a.th=(a.th+1), a.w4=(a.w4&8), b.wl=NULL where a.wid=b.wid and a.wid=;
可以看到sql中既修改了test_info2表,同时修改了wext2表,程序原意是触发得到wext2表wl字段修改后的新值(即NULL);不过实验得到,执行上述sql后,触发器程序查询到的wurl是sql修改之前的旧值。
再执行下面类似sql2:
Update wext2 a, test_info2 b set b.th=(b.th+1), b.w4=(b.w4&8), a.wl=NULL where a.wid=b.wid and a.wid=;
实验的到,执行上述sql后,触发器程序查询到的wurl是sql修改之后的新值。
【原因】原因当然与sql中的别名a,b无关,而是和wext2表和test_info表的书写顺序有关。如本文3.4部分所述,一条sql涉及多个表的 update操作时,数据表字段、触发器执行顺序是mysql源码包装过的。在执行上述sql1时,先执行test_info的更新,然后是after触发器,最后是wext2的更新,也就是说,在执行after触发器时,wext2还没有进行更新,所以触发得到的是旧值。而执行sql2时,先执行 wext2更新,然后是test_info更新,最后是after触发器,也就是说,在执行after触发器时,wext2已经更新完毕,所以出去得到的是新值。
引起上述现象是顺序关系的,无论该表是否支持事务。在使用复杂的sql时,由于有些复杂的sql是mysql自己定义的,所以存在不确定性,存在风险,使用简单的sql比较可控。
5.2&& 案例2 mysql5.0.19版本修改表结构后触发器失效
【现象】userpref表上建有after类型触发器,修改userpref表的外键关联后,在userpref表中的新增记录没有触发下来,即触发器失效。
【原因】mysql5.0.19修改表结构是,触发器消失。这是mysql5.0.19的一个bug,在创建触发器时,会把触发器的内容保存在 information_schema.TRIGGERS表中,同时在var目录下创建触发器的数据库目录下创建一个触发器名称为前缀,以TRN为后缀的文件,当修改触发器的表时,information_schema.TRIGGERS表的内容会删除,导致触发器消失。
在mysql5.0.45版本中,这个bug已经被修复。Mysql5.0.45版本的触发器,无论是修改表的索引、外键,还是改变表字段,触发器都不会失效。
5.3&& 案例3 删除数据表后触发器失效
【现象】联调环境中存在dbA?dbB,主库dbA上没有触发器,在从库dbB上的FC_Word.wnegative表,FC_Word.wbuget 表上建有触发器;触发器开始运行正常,期间没有对从库的任何直接操作,有一日发现对wnegative表上的修改无法触发。查看从库状态,同步正常;用 select TRIGGER_NAME from information_schema.TRIGGERS发现wnegative表上的触发器消失了;在var/FC_Word目录下也没有 wnegative的.TRN文件,wnegative表上的触发器不见了。
【分析】查找dbB的查询日志,发现有一条:
:27:45 135939 Query&&&&&& DROP TABLE IF EXISTS `wnegative`
135939 Query&&&&&& CREATE TABLE `wnegative` (
KEY `Index_wnegative_planid` (`planid`),
KEY `Index_wnegative_unitid` (`unitid`)
135939 Query&&&&&& /*!40000 ALTER TABLE `wnegative` DISABLE KEYS */
:27:46 135939 Query&&&&&& INSERT INTO `wnegative` VALUES (614,1,);
可以看到,在:27:45时,删除了表wnegative,紧接着有创建表wnegative;查找触发表发现,在:27:45时间后对wnegative的修改就没有触发了,而在这个之前对wnegative的修改是触发正常的。故,怀疑对wnegative表的删除使wnegative表上的触发器也被删除。对wnegative表的删除是在主库dbA上操作后,被同步到dbB上。
【原因】在删除wnegative表时,mysql同时删除了wegative表上的触发器。
可以通过下面实验证明上述猜测:
1)&& 首先在wnegative建立after insert型触发器;
2)&& 增加一条wnegative中记录;
3)&& 查看结果发现触发器正确触发;
4)&& 删除wnegative表;
5)&& 使用select TRIGGER_NAME from information_schema.TRIGGERS查看所有触发器,wnegative表上触发器已经不存在了;同时到var/FC_Word目录下,对应触发器的.TRN文件也不存在了;
6)&& 重新创建wnegative表,并增加一条wnegative中记录;没有了wnegative表上触发器,自然也不能触发任何结果。
6&& 结束语
Mysql中的触发器功能已经在凤巢系统的各个模块中有广泛应用,究其细节,还有很多值得注意的地方;本文建立在实验和案例的基础上,数据库基于线上系统使用的mysql5.0.45版本,分析了触发器相关的一些特殊情况下msyql的处理方式。
(全文完)
以上转载自:/baiduqa
后面为实际测试效果所用sql语句
create trigger trigger_tag_insert
before insert
ON tag FOR EACH ROW
update tag set len =& LENGTH(New.tag) where py = New.
drop TRIGGER& trigger_tag_insert
create trigger trigger_tag_insert
before insert
ON tag FOR EACH ROW
set len =& LENGTH(New.tag);
create trigger trigger_tag_insert
before insert
ON tag FOR EACH ROW
set New.len =& LENGTH(New.tag);
在使用中出现错误:Can't update table 'tag' in stored function/trigger because it is already used by statement which invoked this stored function/trigger
/mysql/%E5%85%B3%E4%BA%8Emysql-insert%E8%A7%A6%E5%8F%91%E5%99%A8cant-update-table-tbl%E9%94%99%E8%AF%AF.html
解决以上问题
Can&t update table &tbl& in stored function/trigger because it is already used by statement which invoked this stored function/trigger
链接:/read.php?99,354#msg-122354
when you insert a record mysql is doing some lock stuff. you can&t insert/update/delete rows of the same table where you insert.. because then the trigger would called again and again.. ending up in a recursion。
别人测试的结果是类似这样的触发器在MSSQL, Oracle, DB2, PostgreSQL都没有问题,应该是mysql的一个缺陷,估计会在以后得版本中完成,因为担心陷入死循环,完全可以暴力一点判断再该条语句引发的第三次对该表的操作时,终止该操作,然后给一个waring。mysql目前的做法就是传统的&一个ip出问题,然后封锁一个网段&的做法,mysql因为触发器刚刚推出,再一步一步的完善中。
I think the reason is because a table-level lock is issued while the trigger is running, meaning, no modifications allowed to the calling table by the trigger.
这是另外一个人提出的假设,他假设mysql现在使用触发器时使用的table lock
下面是另外一个人的回帖,对这个是否产生的recursion进行了分析,并给出了测试语句。
What&s that stuff about recursion?
CREATE TABLE a (
id int(11) NOT NULL auto_increment primary key,
updttime datetime
DELIMITER |
CREATE TRIGGER buildref AFTER INSERT ON a
FOR EACH ROW BEGIN
UPDATE a SET a.ref = NEW.id, a.updttime = NOW() WHERE a.id = NEW.
DELIMITER ;
insert into a values(0,0,0) should work!
What&s so recursive about that? The record is created and an update should occur.
There is no way to invoce AFTER INSERT again, because it&s not INSERT but UPDATE.
What&s wrong with that? It runs in Oracle and Informix. Can&t find any reason why this should not work!
解决方法:
I know this is an old post but I stumbled on the answer and thought I would share. During the insert/update you have access to the NEW object which contains all of the fields in the table involved. If you do a before insert/update and edit the field(s) that you want to change in the new object it will become a part of the calling statement and not be executed as a separately (eliminating the recursion)
create trigger test
before update on test
for each row
set NEW.updateTime = NOW();
delimiter |
说白了,就是对该记录的操作将after改成before。
我另外做了一下的测试:
测试版本包括5.0.45和5.1.49
create table test(id serial,value1 int,value2 int);
delimiter |
CREATE TRIGGER t1 AFTER INSERT ON test
FOR EACH ROW BEGIN
update test set value2=value1 where id=NEW.
Can&t update table &test& in stored function/trigger because it is already used by statement which invoked this stored function/trigger
CREATE TRIGGER t1 BEFORE INSERT ON test
FOR EACH ROW BEGIN
SET NEW.value2 =NEW.value1;
CREATE TRIGGER t1 BEFORE INSERT ON test
FOR EACH ROW BEGIN
update test set value2=value1 where id=NEW.id-1;
ERROR 1442 (HY000): Can&t update table &test& in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
因为trigger刚刚加入mysql不久还在剧烈更新中,因此最后再每次添加触发器的时候都要进行详细的测试,能用就OK。[喝小酒的网摘]http://blog./a/7698.htm
相关文章netfilter/iptables IP 信息包过滤系统是一种功能强大的工具,可用于添加、编辑和除去规则,这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则。这些规则存储在专用的信息包过滤表中,而这些表集成在 Linux 内核中。在信息包过滤表中,规则被分组放在我们所谓的链(chain)中。
netfilter/iptables 的最大优点是它可以配置有状态包含最基本,最常用的,测试物理网络的Ping,查看DNS,IP,Mac,TCP,UDP连接查看等经典命令行指令。
1.最基本,最常用的,测试物理网络的
ping 192.168.0.8 -t ,参数-t是等待用户去中断测试
2.查看DNS、IP、Mac等
A.Win98:winipcfg
B.Win2000以上:User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
一些网站常常通过判断 UA 来给不同的操作系统、不同的浏览器发送不同的页面,因此可能造成某些页面无法在某个浏览器中正常显示,但通过伪装 UA 可以绕过检测。
本文是在ASP调用excel分类:电脑知识
在&c:excelook1.xls&存在一个EXCEL表book1.xsl,表的结构如下:
1 序号 名称 金额
2 1 张三 100
3 2 李四 200
4 3 王五 300
序号字段不为空
注意:excel 起始行是1而不是为0ASP错误代码说明
错误代码 错误消息 说明
ASP0100 Out of memory 内存不足(不能分配要求的内存
ASP0101 Unexpected error 意外错误
ASP0102 Expecting string input 缺少字符串输入
ASP0103 Expecting numeric input 缺
IP:118.120.119.223:mysql 两个表同步更新 触发器IP:221.6.15.218:mySQL触发器中多个ifIP:218.94.159.98:mql触发器 unexpected endIP:180.113.26.223:mysql触发多个触发器是什么顺序IP:112.95.146.252:mysql如何查看触发器是否执行 顺序IP:123.64.104.127:触发器+是一条一条执行的吗?IP:115.84.242.146:can+update+table+in+stored+function+trigger+because+it+is+already+used+by+statementIP:58.249.97.162:mysql 触发器 判断 数据 存在IP:58.249.103.179:mysql+触发器++判断+数据+存在IP:211.69.198.153:trigger写入binlogIP:221.12.26.146:MySQL 触发器实验IP:180.175.36.4:mysql 查看触发器是否启动IP:219.68.201.99:觸發器 每次都要新增嗎IP:159.226.10.87:mysql 删除触发器前判断是否存在IP:59.108.16.162:mysql 判断Trigger是否执行IP:122.233.5.189:mysql判断触发器是否存在并删除IP:221.222.124.64:mysql
好像有触发器类型的插件IP:58.216.121.124:mysql 使用触发型事件同步数据到mssql数据库中IP:111.161.79.250:mysql 触发器 判断 NEW OLD 是否相同

我要回帖

更多关于 mysql 触发器 if 的文章

 

随机推荐