zoukankan      html  css  js  c++  java
  • Spring :事务传播行为

    一.相关定义

    事务传播行为(propagation):当前方法的事务如何传播下去(里面的方法如果用事务,是否与它公用一个事务)

    spring中有其中有7种事务传播行为,默认是Reqiured级别。

    public enum Propagation {
    
    	/**
    	 * Support a current transaction, create a new one if none exists.
            如果以前有事务,就用以前的事务,如果没有,就创建一个新的事务。
    	 */
    	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
    
    	/**
    	 * Support a current transaction, execute non-transactionally if none exists.
          支持新的事务,如果没有事务,也可以执行
    	 */
    	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
    
    	/**
    	 * Support a current transaction, throw an exception if none exists.
               当前必须存在事务,否则抛异常
    	 */
    	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
    
    	/**
    	 * Create a new transaction, and suspend the current transaction if one exists.
          创建一个新的事务,并且挂起以前旧的事务
    	 */
    	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
    
    	/**
    	 * Execute non-transactionally, suspend the current transaction if one exists.
               不支持当前存在事务,如果有就挂起当前事务
    	 */
    	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
    
    	/**
    	 * Execute non-transactionally, throw an exception if a transaction exists.
          不支持当前存在事务,如果有就抛异常。
    	 */
    	NEVER(TransactionDefinition.PROPAGATION_NEVER),
    
    	/**
    	 * Execute within a nested transaction if a current transaction exists,
         
         开启一个子事务,mysql不支持,只有支持还原点功能的数据库才行(oracle) */ NESTED(TransactionDefinition.PROPAGATION_NESTED); private final int value; Propagation(int value) { this.value = value; } public int value() { return this.value; } }

    二.相关场景(常用的只有required和requires_new)

    下面针对这两个构建相关场景:

    外事务 {

      A()REQUIRED

      B()REQUIRES_NEW

      C()REQUIRED

      D()REQUIRES_NEW

      //外----

    }

    场景1:A方法出现异常,由于异常机制,导致代码停止,数据库没有任何新的数据进入

    场景2:C方法出现异常,A回滚,B成功,C回滚,D和外无法执行

    场景3:外执行成功后,又抛出异常。外事务感知到异常,A,C,外回滚,B,D成功。

    场景4:D异常,A,C回滚,外执行不了,B成功,D自己回滚

    场景5:C用try-catch执行,C出现异常回滚,外界没有感知到异常,A,B,D,外都成功。

    总结:传播行为过程中,只要requires_new被执行过,就一定成功,required感知到异常就一定会回滚。

      (运行的异常默认是一定回滚的,编译时的异常默认时不会滚的,但是可以用rollbackFor去指定哪些异常一定回滚,noRollbackFor去指定哪些异常不回滚)

    传播行为总是来定义:当一个事务存在时,它内部的事务该怎样执行。

    三.Spring事务失效的一种场景

    看下面一处典型代码

    @Service
    public class TestService {
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void a(){
            b();
            c();
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void b(){
    
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void c(){
    
        }
    }
    

    本来的想法是,b和c自己执行自己,互不干扰,谁抛异常,谁就回滚自己,按事务的传播行为来说,应该是这样,没毛病。

    但是经过测试,你会发现,c如果有异常,那么执行成功的b仍然会回滚,为什么?

    当我们用Controller去调用testService时,发现testService是一个Cglib代理类。

    原因:spring只有被动态代理时才会产生事务,而我们在类的内部,直接调用本类的方法,是不需要经过代理对象的,调用的是TestService本类。

    所以我们只需要由TestService的代理对象去执行相关方法。

    1.导入相关starter

           <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
    

    2.在springboot主应用上开启EnableAspectJAutoProxy注解,并申明可暴露代理对象

     3.在对应的方法中获取代理对象,并使用代理对象去执行方法

    @Service
    public class TestService {
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void a(){
            TestService proxy = (TestService)AopContext.currentProxy();
            proxy.b();
            proxy.c();
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void b(){
    
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void c(){
    
        }
    }
    
  • 相关阅读:
    Android深度探索读书笔记 第四章
    Android深度探索读书笔记 第三章
    Android深度探索读书笔记 第二章
    Android深度探索第九章
    Android深度探索第十章
    Android深度探索第八章
    第六章
    第七章
    第五章
    第四章
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/13604856.html
Copyright © 2011-2022 走看看