大事务拆分项目应用-再看事务嵌套

原创 2018年04月16日 18:13:08

一、何为事务嵌套

最简单的事务嵌套情况:开启了一个事务的情况下,再开启一个事务2。

或者:在t1、t2分别为两个事务操作,而外层t3事务包含t1(t2),t3跟t1(t2)

         OR          

例如在支付系统中,在进行支付校验时,事务1负责更新账单状态&插入历史表,事务2负责创建支付记录及明细,如果假设更新账单状态成功,二创建支付记录失败,则导致账单状态与支付状态丢失数据一致性。故除保证事务1、2的原子性外,还得在1、2上层增加事务3以保证两个事务组合也具有原子性。

二、事务嵌套有何问题?

思考一个问题:理论上,t1事务执行完毕后,如果t2执行失败,往上t3因为t2执行失败而回滚。此时t1能回滚成功么?talk is cheap ,show me the case!测试case如下。

case结果:

1、session1中首先执行开始事务命令, start transaction;然后插入1条记录,查询session1中正常显示
2、在session2中查询该条记录,无匹配结果。 因为此时session1中未执行commit命令。mysql与oracle一样,commit的数据除了当前session之外,其他session是看不到的。
3、直接开启第二个事务,即再一次执行start transaction;此时在session2中,再次查询上一条插入语句,发现可查询到上个事务中插入的记录。表名第二次start transaction命令隐式的触发了第一个事务的commit。
4、在事务2中执行另一个insert语句,然后rollback,第二次insert回滚成功。

case 流程view:

Session1:开启事务1,执行插入后再session1中查询该插入记录:
mysql> start transaction;
Query OK, 0 rows affected

mysql> INSERT into tc_trade_bill_history (bill_id,business_id,need_price,real_price,
total_price,bill_status,operate_name) VALUES (33,1,1,1,1,1,1);
Query OK, 1 row affected

mysql> select * from tc_trade_bill_history where bill_id=33;
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
| id | bill_id | business_id | | operate_name | create_time | settle_price |
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
| 1027031 | 33 | 1 | 1 | 1 | 1 |
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
1 row in set

Session2:session2中查询该记录,返回Empty set
mysql> select * from tc_trade_bill_history where bill_id=33;
Empty set

Session1:session1中开启第二个事务,执行完start transaction命令后,在session2中查询上一个事务的插入数据。
mysql> start transaction;
Query OK, 0 rows affected
session2:查询有结果,表名第二个start transaction隐式的执行了事务1的commit操作。
mysql> select * from tc_trade_bill_history where bill_id=33;
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
| id | bill_id | business_id | create_time | settle_price |
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
| 1027031 | 33 | 1 | 1 | 1 | 1 |
+---------+---------+-------------+------------+------------+-------------+-------------+--------------+---------
1 row in set

从mysql的层面可以看出,mysql是不支持嵌套事务的。开启了一个事务的情况下,再开启一个事务2,会隐式的提交上一个事务。假如此时事务2执行失败,再rollback,并不能使得事务1回滚成功(事务2是可以rollback成功的)。同理,如果出现其他业务场景的的事务嵌套,例如先开启t1,然后开启t2,t1、t2包裹在t3中,在执行开启t2时,t1已经被隐式commit了。如果此时t2执行失败,导致t2回滚,外部t3也跟着需要回滚,此时只能保证t2、t3回滚成功,而t1无法回滚。
注:
增加一个autocommit的介绍,autocommit是mysql中的InnoDb数据表特有的语句。(只有在表引擎=InnoDb时,autocommit才会生效)。执行set autocommit = 1; 设置mysql 为自动提交(默认即为1),即将每个sql当做事务执行,sql末尾,默认执行一次commit。但这个设置对有事务的sql就不奏效,事务必须显示的执行commit才可提交事务。

三、Spring事务传播属性(简单介绍,不做重点讨论,详见:Spring事务传播特性的浅析

Spring通过设置事务传播行为来控制多个事务方法相互调用时,事务如何在这些方法间传播。
  • PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。这是最常见的选择。
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。以required属性为例
Spring为UserService#logon()方法启动了一个新的事务,而UserSerive#updateLastLogonTime()和UserService#logon()是在相同的类中,没有观察到有事务传播行为的发生,其代码块好像“直接合并”到UserService#logon()中。 然而在执行到ScoreService#addScore()方法时,我们就观察到发生一个事务传播的行为:" Participating in existing transaction ",这说明ScoreService#addScore()添加到UserService#logon()的事务上下文中,两者共享同一个事务所以最终的结果是UserService的logon()、updateLastLogonTime()以及ScoreService的addScore都工作于同一事务中。 

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Daybreak1209/article/details/79956172

性能优化-采用切分小事务方式提升性能

尽量避免使用大事务操作,这样会导致严重的性能问题,可根据实际业务切分为小的业务点进行处理;技术方面,可分析代码,在原业务不发生变化的前提下切分为更小的事务块进行优化。 案例:       ...
  • u011392148
  • u011392148
  • 2014-02-13 17:42:48
  • 802

服务器设计:事务拆分和异步

服务器设计:事务拆分和异步 现在来看,基本上所有通常意义上稍有点规模的服务器程序(这里指的是至少能够容纳数千以上客户端的服务器程序),不可避免的要涉及到远程调用和数据库操作。这两种操作都是时延比较长的...
  • igame
  • igame
  • 2007-08-29 17:02:00
  • 1794

SqlServer 复制中将大事务分成小事务分发

在sql server 复制中,当在发布数据库执行1个大事务时,如一次性操作 十万或百万以上的数据。当操作数据在发布数据库执行完成后 ,日志读取器代理将扫描事务日志,一次性传递到分发数据库中。若上个事...
  • kk185800961
  • kk185800961
  • 2015-05-30 19:17:55
  • 2066

Spring事务传播特性的浅析——事务方法嵌套调用的迷茫

Spring事务传播机制回顾     Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务。结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就...
  • hy6688_
  • hy6688_
  • 2015-03-31 00:49:21
  • 23078

Java中的事务——全局事务与本地事务

在上一篇文章中说到过,Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。这是从事务的实现角度区分的,本文从另外一个角度来再次区分一下Java中的...
  • w372426096
  • w372426096
  • 2017-11-19 14:07:52
  • 139

MySQL嵌套事务的讨论

看MySQL Internals Manual文档有一段关于nest
  • w18704622664
  • w18704622664
  • 2014-07-22 11:29:33
  • 4495

别使用嵌套事务

公司之前一直存在一个规范,就是禁止嵌套事务的使用,一直不太明白为什么,试了下应该是无法控制回滚,今天看大牛的博客发现,问题远远不只如此。 具体总结下来是以下3个问题 1、内层事务回滚,只能回滚全部...
  • starseeker7
  • starseeker7
  • 2013-02-05 11:40:42
  • 14522

mysql嵌套事务的问题

今天跟同事在讨论一段代码,我建议使用嵌套事务解决。当场用mysql示范,结果发现了一下问题 这时候另一个链接中会看到value=1. 查了资料: Transactions cannot...
  • superscorpio
  • superscorpio
  • 2016-01-21 13:45:36
  • 1996

大事务拆分项目应用及系统异步化处理-再看分布式事务

Case1一、交易还款业务大事务废话不多说,直接一个金融还款业务创建交易账单case,还款逻辑如下:1、用户点击还款,发起还款请求2、服务端接收还款请求,进行还款计划查询校验3、进行其他还款验证4、返...
  • Daybreak1209
  • Daybreak1209
  • 2018-04-10 12:06:23
  • 85

什么是嵌套事务?

什么是嵌套事务? 嵌套事务是一个外部事务的一个子事务,是一个外部事务的一个组成部分,当嵌套事务发生异常,而回滚,则会回复到嵌套事务的执行前的状态,相当于嵌套事务未执行。 如果外部事务回滚...
  • u014698348
  • u014698348
  • 2016-11-12 18:54:26
  • 2674
收藏助手
不良信息举报
您举报文章:大事务拆分项目应用-再看事务嵌套
举报原因:
原因补充:

(最多只允许输入30个字)