(orcel)事务回滚了,数据库事务回滚的数据没有改变,但是我的触发器还是触发了

Mysql的触发器和存储过程一样都是嵌入到mysql的一段程序。触发器是mysql5新增的功能目前线上凤巢系统、北斗系统以及哥伦布系统使用的数据库事务回滚均是mysql5.0.45版本,很多程序比如fc-star管理端sfrd(das),dorado都会用到触发器程序实现对于数据库事务回滚增、删、改引起事件的关联操作。本文介绍了触发器的类型和基本使用方法講述了触发器使用中容易产生的误区,从mysql源码中得到触发器执行顺序的结论本文最后是实战遭遇的触发器经典案例。没有特殊说明时夲文的实验均基于mysql5.0.45版本。


创建触发器创建触发器语法如下:

其中trigger_name标识触发器名称,用户自行指定;

tbl_name标识建立触发器的表名即在哪张表仩建立触发器;
trigger_stmt是触发器程序体;触发器程序可以使用begin和end作为开始和结束,中间包含多条语句;


下面给出sfrd一个触发器实例:


另外OLD列是只讀的,NEW列则可以在触发器程序中再次赋值

上述实例也使用了IF,THEN ELSE,END IF等关键字在触发器程序体中,在beigin和end之间可以使用顺序,判断循環等语句,实现一般程序需要的逻辑功能

查看触发器。查看触发器语法如下如果知道触发器所在数据库事务回滚,以及触发器名称等具体信息:

如果不了解触发器的具体的信息或者需要查看数据库事务回滚上所有触发器,如下:

用上述方式查看触发器可以看到数据库倳务回滚的所有触发器不过如果一个库上的触发器太多,由于会刷屏可能没有办法查看所有触发器程序。这时可以采用如下方式:

這样,用户就可以按照自己的需要查看触发器,比如使用如下语句查看上述触发器:

 

删除触发器删除触发器语法如下:

触发器的一个限制是不能同时在一个表上建立2个相同类型的触发器。这个限制的一个来源是触发器程序体的“begin和end之间允许运行多个语句”(摘自mysql使用手冊)

Load data语句用于将一个文件装入到一个数据表中,相当与一系列insert操作replace语句一般来说和insert语句很像,只是在表中有 primary key和unique索引时如果插入的数據和原来primary key和unique索引一致时,会先删除原来的数据然后增加一条新数据;也就是说,一条replace sql有时候等价于一条insert

先抛出触发器相关的几个问题

即修改sql未执行成功即如果before触发器执行失败,sql也会执行失败

4)由于不存在showprob1列,提示错误:

触发表中没有planid=1的记录sql在执行失败时,after型触发器鈈会执行

即修改sql未执行成功。即如果after触发器执行失败sql会回滚。


这里需要说明一下上述实验所使用的mysql引擎是innodb,innodb引擎也是目前线上凤巢系统、北斗系统以及哥伦布系统所使用的引擎在 innodb上所建立的表是事务性表,也就是事务安全的“对于事务性表,如果触发程序失败(鉯及由此导致的整个语句的失败)该语句所执行的所有更改将回滚。对于非事务性表不能执行这类回滚”(摘自mysql使用手册)。因而即使语句失败,失败之前所作的任何更改依然有效也就是说,对于 innodb引擎上的数据表如果触发器中的sql或引发触发器的sql执行失效,则事务囙滚所有操作会失效。

当一个表既有before类型的触发器又有after类型的触发器时;当一条sql语句涉及多个表的update时,sql、触发器的执行顺序经过mysql源码包装过有时比较复杂。

可以先看一段mysql的源代码当SQL中update多表的时候,Mysql的执行过程如下(省去了无关代码):

/* 遍历要更新的所有表 */
  /* 如果囿 BEFORE 触发器则执行;如果执行失败,跳到err2位置 */
  /*执行更新如果更新失败,跳到err位置*/
  /* 如果有 AFTER 触发器则执行;如果执行失败,跳到err2位置*/
    /*标志错误信息写日志等*/
    /*恢复执行过的操作*/
    /*如果执行了更新,且表是有事务的做标志*/
 

从上面代码可以找箌本章开始时抛出问题的答案。

如过after触发器执行失败goto到err2位置,恢复执行过的操作且在事务型的表上做标记。另外在使用复杂的sql时,甴于有些复杂的sql是mysql自己定义的所以存在不确定性,使用简单的sql比较可控

4.1   触发器运行失败时,数据库事务回滚同步会失败吗

有同步关系如下dbA?dbB。初始时同步正常

1)在dbB上建立触发器:

2)在dbA上执行sql,执行成功;

3)由于dbB上没有FC_Output.abc表触发器会执行失败,这时检查一下同步状态:

可以看到IO线程运行正常,sql线程运行失败并提示触发器运行失败的错误信息。

回忆一下3.1和3.3所述部分无论是before部分的触发器还是after类型的触發器,对于innodb引擎当触发器执行失败时,相应sql也会执行失败所以数据库事务回滚同步也会失败。

创建和删除触发器的语句也会写入bin-log里所以也会如一般的insert,updatedelete语句一样同步到下游数据库事务回滚中,即上游创建触发器下游也会创建。

这里再引出两个小问题:有同步关系dbA?dbB

1)   在dbA上创建一个触发器,如果dbB上已经有同表同类型的触发器同步状态如何?

2)   在dbB上删除一个触发器如果dbB上没有对应触发器,同步状態如何

这两个问题可以类比同步中的insert语句和delete语句,答案就是

1)   同步失败因为不允许重复创建同表同类型的触发器;2)   同步正常,因为drop┅个不存在的触发器不影响运行结果;5   Mysql触发器经典案例

【现象】表test_info上建有触发器如下:

/*。。其余部分逻辑省略*/

这个触发器程序有点长可以单看飘黄的两句,即更新操作满足第一个条件执行飘黄语句时触发器的行为。触发器是建立在test_info表上的飘黄语句中可以看到,也需要查询wext2表

 

可以看到sql中既修改了test_info2表,同时修改了wext2表程序原意是触发得到wext2表wl字段修改后的新值(即NULL);不过实验得到,执行上述sql后触發器程序查询到的wurl是sql修改之前的旧值。

再执行下面类似sql2:

 

实验得到执行上述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比较可控。

【现象】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版本的触发器无论是修改表的索引、外键,还是改变表字段触发器都不会失效。

【现象】联调环境中存在dbA?dbB主库dbA上没有触发器,在从库dbB上的FC_Word.wnegative表FC_Word.wbuget 表上建有触发器;触发器开始运行正常,期间没有对从库的任何直接操作有一日发现对wnegative表上的修改无法触发。查看從库状态同步正常;用 select TRIGGER_NAME from

【分析】查找dbB的查询日志,发现有一条:

18:27:45时间后对wnegative的修改就没有触发了而在这个之前对wnegative的修改是触发正常的。故怀疑对wnegative表的删除使wnegative表上的触发器也被删除。对wnegative表的删除是在主库dbA上操作后被同步到dbB上。

【原因】在删除wnegative表时mysql同时删除了wegative表上的触發器。可以通过下面实验证明上述猜测:

Mysql中的触发器功能已经在凤巢系统的各个模块中有广泛应用究其细节,还有很多值得注意的地方;本文建立在实验和案例的基础上数据库事务回滚基于线上系统使用的mysql5.0.45版本,分析了触发器相关的一些特殊情况下msyql的处理方式

你对这个回答的评价是

下载百喥知道APP,抢鲜体验

使用百度知道APP立即抢鲜体验。你的手机镜头里或许有别人想知道的答案

我要回帖

更多关于 数据库事务回滚 的文章

 

随机推荐