zoukankan      html  css  js  c++  java
  • Spring事务传递性探讨

    本篇主要讨论下面几点获取【下载地址】  

    一: Spring 事务的传递性介绍

    二: 第三方调用含有事务的Service抛异常方法探讨

    一: Spring 事务的传递性介绍

        事务传播行为,所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

        TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

        TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

        TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

        TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

        TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

        TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

        TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价TransactionDefinition.PROPAGATION_REQUIRED。

        这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉 JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。

    二: 第三方调用含有事务的Service抛异常方法探讨

        假设术语如下:调用方Conumer,  调用Service的methodA, methodA调用Service的 methodB

        a)methodA 传播属性为required, methodB传播属性为required, 代码如下

         

    Java代码  收藏代码
    1. public void methodA() {  
    2.     try {  
    3.        methodB();  
    4.     } catch(Exception e) {  
    5.        process();  
    6.     }  
    7.     otherOperation;  
    8. }  
     
        假设MethodB抛出异常,则Consumer调用MethodA会发生怎样的情形? 

        发现Consumer调用MethodA的时候出现了运行时异常,UnexpectedRollbackException: “Transaction rolled back because it has been marked as rollback-only”。这是为什么呢?

        网上搜索了下,终于发现了一个合理的解释。当MethodA调用MethodB的时候,且两个方法都为required属性,则methodA和methodB共享一个事务,当methodB抛出了异常,则共享事务回滚,但是被MethodA catch了,而MethodA又没有及时抛出异常,则MethodA正常执行到最后的时候,则会做提交事务的操作,但是事务已经被回滚了,所以才出现了上面的异常。

        既然这样,小弟就开始YY了一下,哪些情况会使调用方没有这个异常呢?经过与小伙伴们的思维碰撞,发现有一下几个方法。

       b) MethodA 不加事务,所以执行到最后就不会commit,SUPPORTS和NOT_SUPPORTED都可以实现这种功能。

       c) MethodB 设置不共享事务,拥有自己单独的事务。验证发现,REQUIRES_NEW可以实现这种功能。

       

       然后又YY了下,既然一个回滚的事务不能提交了,那么这个回滚的事务可以重复回滚吗?

       d) MethodA 调用MethodB,如果MethodA不catch MethodB,则调用方会怎么样?很简单当然直接捕获到MethodB的异常了,但是感觉这个场景不能完全反应初回滚的事务是否可以重复回滚。代码如下:

    Java代码  收藏代码
    1. public void methodA() {  
    2.     methodB();  
    3.     otherOperation;  
    4. }  

      e) 还有什么场景可以模拟回滚的事务是否可以再回滚呢?看,代码如下:

         

    Java代码  收藏代码
    1. public void methodA() {  
    2.     try {  
    3.        methodB();  
    4.     } catch(Exception e) {  
    5.        process();  
    6.     }  
    7.     try {  
    8.        methodB();  
    9.     } catch(Exception e) {  
    10.        process();  
    11.     }  
    12.     System.out.println("**************");  
    13.     otherOperation;  
    14. }  

       第一个MethodB已经回滚了共享的事务,第二个MethodB同样会抛出异常回滚共享的事务,如果执行了后面的System.out,则说明事务可以多次回滚。测试发现打印出来了后面的SysOut的内容,所以猜测可能是这样回滚事务的时候如果发现事务已经回滚,则直接跳过。

  • 相关阅读:
    Java学习笔记 -StringBuffer & StringBuilder
    Java学习笔记
    java学习笔记 -数组
    关于运放采集电路如何自动切换量程电路
    仪器仪表运放的放大倍数的一些问题
    二极管、三极管和mos管使用总结
    mos管缓启动和防反接电路原理
    关于产生负电源电路
    可靠性测试之画pcb
    AD软件pcb电路板各图层的理解
  • 原文地址:https://www.cnblogs.com/koliop090/p/5203539.html
Copyright © 2011-2022 走看看