`

关于spring事务传播特性的相关问题的解释

阅读更多

      昨天帮助同事解决一个问题,其中遇到一个问题涉及到spring的事务,当时有点不敢肯定,做了实验,并参考了其他同仁的,做了些总结,希望能帮助到大家。

 
我们首先先来看下spring的事务的传播特性:

事务传播行为类型

说明

PROPAGATION_REQUIRED

如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

 
当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。
 
我们现在挨个来讲解下这个里面容易误解的几个:
 
1. PROPAGATION_REQUIRED
    假设有下面代码:
ServiceA {

    /**  

     * 事务属性配置为 PROPAGATION_REQUIRED  

     */  

    void methodA() {   

       try {

           ServiceB.methodB(); 

       } catch(Exception e){

          e.printstacktrace();

       }  

    }   

} 

ServiceB {

    /**  

     * 事务属性配置为 PROPAGATION_REQUIRED  

     */    

    void methodB() {   

    }   

}  
 
      其实required从我面试候选人来看,基本上都能答出来,但是看到上面的情景是回滚还是提交,基本上答上来的很少,我们再来看下定义,如果当前没有事务,就开启一个,如果有就加入到这个事务里面,也就是说整个是一个事务,所以B发生异常,会导致整个事务一块回滚。从这个里面可以看到,简单的将methodB异常捕获,认为整个事务会提交,其实是不行的。
 
     2. PROPAGATION_REQUIRES_NEW
    
ServiceA {

    /**  

     * 事务属性配置为 PROPAGATION_REQUIRED  

     */  

    void methodA() {   

       try {

           ServiceB.methodB(); 

       } catch(Exception e){

          e.printstacktrace();

       }  


    }   

} 

ServiceB {

    /**  

     * 事务属性配置为 PROPAGATION_REQUIRES_NEW  

     */    

    void methodB() {   

    }   

}  
      requires new这种类型,基本上所有的人都能答正确,A和B是两个独立的事务,内外两个事务没有任何影响,结果是B回滚,A提交
  
   3. PROPAGATION_REQUIRED
    
ServiceA {

    /**  

     * 事务属性配置为 PROPAGATION_REQUIRED  

     */  

    void methodA() {   

       try {

           ServiceB.methodB(); 

       } catch(Exception e){

          e.printstacktrace();

       }  

    }   

} 

ServiceB {

    /**  

     * 事务属性配置为 PROPAGATION_NESTED  

     */    

    void methodB() {   

    }   

}  
 
    从概念来看,有一个嵌套事务出现了
    我们来分析下这个,首先我们先根据一个图将这个分解下:
   

    (上图A、B、C、D代表几个时机,我们用AD和BC代表这两个事务,1,2,3代表事务执行的三个阶段)
     嵌套事务达到的效果如下:
     1.  事务BC与事务AD一起commit,即:作为事务AD的子事务,事务BC只有在事务AD成功commit时(阶段3成功)才commit。这个需求简单称之为“联合成功”
     2.  事务BC的rollback不影响事务AD的commit
    也就是说第一个是required的特性,第二个是requires new的特性
 
     当BC事务成功commit时,PROPAGATION_NESTED的行为与PROPAGATION_REQUIRED一样。只有当事务AD在D点成功commit时,事务BC才真正commit,如果阶段3执行异常,导致事务AD rollback,事务BC也将一起rollback ,从而满足了“联合成功”
 
     当阶段2执行异常,导致BC事务rollback时,因为设置了savePoint,AD事务可以选择与BC一起rollback或继续阶段3的执行并保留阶段1的执行结果,从而满足了“隔离失败”。
 
      强调,补充一点:PROPAGATION_NESTED只是Spring针对JDBC3.0以上版本SavePoint机制的一个事务传播机制的扩展,J2EE体系中是没有的,所以如果应用中使用JTA作为底层的事务管理机制的话,使用Spring也是不可能支持PROPAGATION_NESTED。

 

 
  • 大小: 25.9 KB
4
0
分享到:
评论
1 楼 caolinhuadeeper 2014-09-25  
从这个里面可以看到,简单的将methodB异常捕获,认为整个事务会提交,其实是不行的。
这个说法,应该是对的。methodB异常捕获,methodA继续执行,提交事务。只不过日志中【抛出methodB的异常信息

相关推荐

Global site tag (gtag.js) - Google Analytics