Spring嵌套事务解惑(重点)

本文详细解释了Spring框架中事务管理的七个传播级别,包括PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS等,并通过对比PROPAGATION_REQUIRES_NEW与PROPAGATION_NESTED的特点,帮助读者理解不同传播级别在实际应用中的作用。

http://www.iteye.com/topic/35907

PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。 
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager

 PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
  另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. 

PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行. 
  另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. 
  由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back. 

  由此可见,

PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于,

PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而

PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit,

这个规则同样适用于 roll back. 

当然, 就算所有嵌套事务都已经成功, 外部事务还是可能因为嵌套事务的执行结果而导致失败,  此时整个事务都要 roll back ,这也是嵌套事务的重要特性之一, 即外部事务和嵌套事务互相影响

只有需要根据子事务的执行情况进行分支处理的情况下才是nested的用武之地, savepoint是嵌套事务回滚的实现方式 需要注意的是使用它的限制条件

使用嵌套事务是有前提的,就是该嵌套事务可能需要做分支处理。否则用 PROPAGATION_REQUIRED 就足够了,如果子事务有异常,直接回滚。

nested 可以在外层rollback所有内层的事务。requiresnew 不行。

例子:

  1. ServiceA {  
  2.       
  3.     /** 
  4.      * 事务属性配置为 PROPAGATION_REQUIRED 
  5.      */  
  6.     void methodA() {  
  7.         ServiceB.methodB();  
  8.     }  
  9.   
  10. }  
  11.   
  12. ServiceB {  
  13.       
  14.     /** 
  15.      * 事务属性配置为 PROPAGATION_REQUIRES_NEW 
  16.      */   
  17.     void methodB() {  
  18.     }  
  19.       
  20. }     

 

PROPAGATION_REQUIRES_NEW 时 ServiceB.methodB 没办法回滚到它执行之前的 SavePoint, 这时已经产生了一些脏数据, 而这些脏数据将可能导致后面的程序执行出错

 

  1. ServiceA {  
  2.       
  3.     /** 
  4.      * 事务属性配置为 PROPAGATION_REQUIRED 
  5.      */  
  6.     void methodA() {  
  7.         try{
  8.         ServiceB.methodB();  
  9.         }catch(Exeception e){
  10.          ServiceC.methodC();
  11.        }
  12.     }  
  13.   
  14. }  
  15.   
  16. ServiceB {  
  17.       
  18.     /** 
  19.      * 事务属性配置为 PROPAGATION_NESTED 
  20.      */   
  21.     void methodB() {  
  22.     }  
  23.       
  24. }     

对于PROPAGATION_NESTED 的嵌套事务而言,如果 ServiceB.methodB()异常,会会回滚到上一个savepoint点,外层事务A,可以捕获,处理ServiceC.methodC(),但是对于ServiceA.methodA()异常,会回滚整个嵌套的事务

转载于:https://my.oschina.net/wangen2009/blog/1838511

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值