• Spring事务的传播:PROPAGATION_REQUIRED


    PROPAGATION_REQUIRED-- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 

    1. ServiceA {           
    2.      void methodA() {  
    3.          ServiceB.methodB();  
    4.      }  
    5. }      
    6. ServiceB {           
    7.      void methodB() {  
    8.      }           
    9. }  

    PROPAGATION_REQUIRED

    假如当前正要执行的事务不在另外一个事务里,那么就起一个新的事务 
    比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候
      1、如果ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。这时只有外部事务并且他们是共用的,所以这时ServiceA.methodA或者ServiceB.methodB无论哪个发生异常methodA和methodB作为一个整体都将一起回滚。
      2、如果ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。这样,在ServiceA.methodA中是没有事务控制的。只是在ServiceB.methodB内的任何地方出现异常,ServiceB.methodB将会被回滚,不会引起ServiceA.methodA的回滚
    -----------------以上为重点内容----------------以下为引用全文------------

     

    事务的嵌套概念

    所谓事务的嵌套就是两个事务方法之间相互调用。spring事务开启 ,或者是基于接口的或者是基于类的代理被创建(注意一定要是代理,不能手动new 一个对象,并且此类(有无接口都行)一定要被代理——spring中的bean只要纳入了IOC管理都是被代理的)。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的。
     
    ###
    Spring默认情况下会对运行期例外(RunTimeException),即uncheck异常,进行事务回滚。
    如果遇到checked异常就不回滚。
    如何改变默认规则:

    1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)


    2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)


    3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
    上面三种方式也可在xml配置
     

    spring事务传播属性

     在 spring的 TransactionDefinition接口中一共定义了六种事务传播属性:
     
    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) 
     
     
    举例浅析Spring嵌套事务
    ServiceA#methodA(我们称之为外部事务),ServiceB#methodB(我们称之为外部事务)
     
    [java] view plain copy
     
     
     
     
    1. ServiceA {  
    2.          
    3.      void methodA() {  
    4.          ServiceB.methodB();  
    5.      }  
    6.     
    7. }  
    8.     
    9. ServiceB {  
    10.          
    11.      void methodB() {  
    12.      }  
    13.          
    14. }  
     

    PROPAGATION_REQUIRED

    假如当前正要执行的事务不在另外一个事务里,那么就起一个新的事务 
    比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候
      1、如果ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。这时只有外部事务并且他们是共用的,所以这时ServiceA.methodA或者ServiceB.methodB无论哪个发生异常methodA和methodB作为一个整体都将一起回滚。
      2、如果ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。这样,在ServiceA.methodA中是没有事务控制的。只是在ServiceB.methodB内的任何地方出现异常,ServiceB.methodB将会被回滚,不会引起ServiceA.methodA的回滚
     

    PROPAGATION_SUPPORTS

    如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行 

    PROPAGATION_MANDATORY

    必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常

    PROPAGATION_REQUIRES_NEW

    启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行. 
     比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。
    1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
    2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
     
    使用场景:
    不管业务逻辑的service是否有异常,Log Service都应该能够记录成功,所以Log Service的传播属性可以配为此属性。最下面将会贴出配置代码。
     

    PROPAGATION_NOT_SUPPORTED

    当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。

    PROPAGATION_NEVER

    不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。 

    PROPAGATION_NESTED

    开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. 
     
    比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_NESTED,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint,等待ServiceB.methodB的事务完成以后,他才继续执行。。因为ServiceB.methodB是外部事务的子事务,那么
    1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB也将回滚。
    2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
    理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是:
    PROPAGATION_REQUIRES_NEW 完全是一个新的事务,它与外部事务相互独立; 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back. 
     

    在 spring 中使用 PROPAGATION_NESTED的前提:

    1. 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!! 

    2. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+ 

    3. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0 


    确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了. 
     
     
    ##############################################################################

    Log Service配置事务传播

    不管业务逻辑的service是否有异常,Log Service都应该能够记录成功,通常有异常的调用更是用户关心的。Log Service如果沿用业务逻辑Service的事务的话在抛出异常时将没有办法记录日志(事实上是回滚了)。所以希望Log Service能够有独立的事务。日志和普通的服务应该具有不同的策略。Spring 配置文件transaction.xml:
    [html] view plain copy
     
     
     
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    4.     xmlns:tx="http://www.springframework.org/schema/tx"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
    6.     <!-- configure transaction -->  
    7.   
    8.     <tx:advice id="defaultTxAdvice" transaction-manager="transactionManager">  
    9.         <tx:attributes>  
    10.             <tx:method name="get*" read-only="true" />  
    11.             <tx:method name="query*" read-only="true" />  
    12.             <tx:method name="find*" read-only="true" />  
    13.             <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
    14.         </tx:attributes>  
    15.     </tx:advice>  
    16.   
    17.     <tx:advice id="logTxAdvice" transaction-manager="transactionManager">  
    18.         <tx:attributes>  
    19.             <tx:method name="get*" read-only="true" />  
    20.             <tx:method name="query*" read-only="true" />  
    21.             <tx:method name="find*" read-only="true" />  
    22.             <tx:method name="*" propagation="REQUIRES_NEW"  
    23.                 rollback-for="java.lang.Exception" />  
    24.         </tx:attributes>  
    25.     </tx:advice>  
    26.   
    27.     <aop:config>  
    28.         <aop:pointcut id="defaultOperation"  
    29.             expression="@within(com.homent.util.DefaultTransaction)" />  
    30.         <aop:pointcut id="logServiceOperation"  
    31.             expression="execution(* com.homent.service.LogService.*(..))" />  
    32.               
    33.         <aop:advisor advice-ref="defaultTxAdvice" pointcut-ref="defaultOperation" />  
    34.         <aop:advisor advice-ref="logTxAdvice" pointcut-ref="logServiceOperation" />  
    35.     </aop:config>  
    36. </beans>  
     
     如上面的Spring配置文件所示,日志服务的事务策略配置为propagation="REQUIRES_NEW",告诉Spring不管上下文是否有事务,Log Service被调用时都要求一个完全新的只属于Log Service自己的事务。通过该事务策略,Log Service可以独立的记录日志信息,不再受到业务逻辑事务的干扰。
  • 相关阅读:
    BZOJ1001 BJOI2006狼抓兔子(最小割+最短路)
    BZOJ4569 SCOI2016萌萌哒(倍增+并查集)
    Luogu4782 【模板】2-SAT 问题(2-SAT)
    BZOJ3626 LNOI2014LCA(树链剖分+主席树)
    BZOJ4012 HNOI2015开店(树链剖分+主席树)
    Luogu2264 树上游戏(点分治)
    BZOJ3998 TJOI2015弦论(后缀数组+二分答案)
    BZOJ1045 HAOI2008糖果传递(贪心)
    BZOJ1124 POI2008枪战Maf(环套树+贪心)
    洛谷 P4568 [JLOI2011]飞行路线 解题报告
  • 原文地址:https://www.cnblogs.com/shenzhichipingguo/p/9186211.html
Copyright © 2020-2023  润新知