zoukankan      html  css  js  c++  java
  • 事务分析(二) 事务传播

    事务传播分析 @Transaction Propagation


     一.源码中的7种事务传播类型

    public enum Propagation {
        REQUIRED(0),
        SUPPORTS(1),
        MANDATORY(2),
        REQUIRES_NEW(3),
        NOT_SUPPORTED(4),
        NEVER(5),
        NESTED(6);
    
        private final int value;
    
        private Propagation(int value) {
            this.value = value;
        }
    
        public int value() {
            return this.value;
        }
    }

    7种事务的翻译:

    事务传播类型
    英文注释
    中文翻译
    REQUIRED       
    /**
    * Support a current transaction, create a new one if none exists.
    * Analogous to EJB transaction attribute of the same name.
    * <p>This is the default setting of a transaction annotation.
    */

    支持当前事务,如果不存在则创建新事务

    PS:这是事务注解(@Transactional)的默认设置

    SUPPORTS
    /**
    * Support a current transaction, execute non-transactionally if none exists.
    * Analogous to EJB transaction attribute of the same name.
    * <p>Note: For transaction managers with transaction synchronization,
    * {@code SUPPORTS} is slightly different from no transaction at all,
    * as it defines a transaction scope that synchronization will apply for.
    * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
    * will be shared for the entire specified scope. Note that this depends on
    * the actual synchronization configuration of the transaction manager.
    * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
    */
    支持当前事务,如果不存在,则非事务性执行
    MANDATORY
    /**
    * Support a current transaction, throw an exception if none exists.
    * Analogous to EJB transaction attribute of the same name.
    */
    支持当前事务,如果不存在事务,则引发异常
    REQUIRES_NEW
    /**
    * Create a new transaction, and suspend the current transaction if one exists.
    * Analogous to the EJB transaction attribute of the same name.
    * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    * on all transaction managers. This in particular applies to
    * {@link org.springframework.transaction.jta.JtaTransactionManager},
    * which requires the {@code javax.transaction.TransactionManager} to be
    * made available to it (which is server-specific in standard Java EE).
    * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
    */
    创建一个新事务,如果当前事务存在,则挂起当前事务
    NOT_SUPPORTED
    /**
    * Execute non-transactionally, suspend the current transaction if one exists.
    * Analogous to EJB transaction attribute of the same name.
    * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    * on all transaction managers. This in particular applies to
    * {@link org.springframework.transaction.jta.JtaTransactionManager},
    * which requires the {@code javax.transaction.TransactionManager} to be
    * made available to it (which is server-specific in standard Java EE).
    * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
    */
    非事务性执行,如果当前事务存在,则挂起当前事务
    NEVER
    /**
    * Execute non-transactionally, throw an exception if a transaction exists.
    * Analogous to EJB transaction attribute of the same name.
    */
    以非事务方式执行,如果事务存在,则抛出异常
    NESTED
    /**
    * Execute within a nested transaction if a current transaction exists,
    * behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.
    * <p>Note: Actual creation of a nested transaction will only work on specific
    * transaction managers. Out of the box, this only applies to the JDBC
    * DataSourceTransactionManager. Some JTA providers might support nested
    * transactions as well.
    * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
    */
    如果当前事务存在,则在嵌套事务中执行

    二.事务传播类型分析

     1.REQUIRED 支持当前事务,如果不存在则创建新事务   

    //场景1
    public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
            
        }
    
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景2
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景3
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
            System.err.println(1/0);
        }
    
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation2(){
            userMapper.insert("老钱",84);
    
        }
    View Code
    方法名称  propagation1 propagation2 结果
    事务配置场景1     无事务   
    异常放到propagation2:System.err.println(1/0);
    @Transactional(propagation = Propagation.REQUIRED)

    小李录入数据库成功

    老钱录入数据库失败

    事务配置场景2
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0);
    @Transactional(propagation = Propagation.REQUIRED)

    小李录入数据库失败

    老钱录入数据库失败

    事务配置场景3
    异常放到propagation1:System.err.println(1/0);
    @Transactional(propagation = Propagation.REQUIRED)
     
    @Transactional(propagation = Propagation.REQUIRED)
     

    小李录入数据库失败

    老钱录入数据库失败

    小结:子事务是 REQUIRED  时,父方法存在事务则加入父事务,回滚服从父事务的执行情况.

    2.SUPPORTS 支持当前事务,如果不存在,则非事务性执行

    方法名称 propagation1 propagation2 结果
    事务配置场景1 无事务
    异常放到propagation2:System.err.println(1/0)
    @Transactional(propagation = Propagation.SUPPORTS)

    小李录入数据库成功

    老钱录入数据库成功

    事务配置场景2
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0)
    @Transactional(propagation = Propagation.SUPPORTS)

    小李录入数据库失败

    老钱录入数据库失败

    3.MANDATORY 支持当前事务,如果不存在事务,则引发异常

    //场景1
    
    @Service
    public class TestPropagationService1 {
    
        @Autowired
        UserMapper userMapper;
    
        @Autowired
        TestPropagationService2 service2;
    
        //@Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    }
    
    @Service
    public class TestPropagationService2 {
    
    
        @Autowired
        UserMapper userMapper;
        @Transactional(propagation = Propagation.MANDATORY )
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    }
    View Code
    //场景2
    @Service
    public class TestPropagationService1 {
    
        @Autowired
        UserMapper userMapper;
    
        @Autowired
        TestPropagationService2 service2;
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    }
    
    @Service
    public class TestPropagationService2 {
    
    
        @Autowired
        UserMapper userMapper;
        @Transactional(propagation = Propagation.MANDATORY )
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    }
    View Code
    方法名称 propagation1 propagation2 结果
    事务配置场景1 无事务
    @Transactional(propagation = Propagation.MANDATORY)

    小李录入数据库成功

    老钱录入数据库失败

    事务配置场景2
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0)
    @Transactional(propagation = Propagation.MANDATORY)

    小李录入数据库失败

    老钱录入数据库失败

    4.REQUIRES_NEW 创建一个新事务,如果当前事务存在,则挂起当前事务

    //场景1
    //@Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景2
    @Autowired
        UserMapper userMapper;
    
        @Autowired
        TestPropagationService2 service2;
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景3
    
    @Autowired
        UserMapper userMapper;
    
        @Autowired
        TestPropagationService2 service2;
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
            System.err.println(1/0);
        }
    
    
    @Autowired
        UserMapper userMapper;
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void propagation2(){
            userMapper.insert("老钱",84);
    
        }
    View Code
    方法名称 propagation1 propagation2 结果
    事务配置场景1 无事务
    异常放到propagation2:System.err.println(1/0)
    @Transactional(propagation = Propagation.REQUIRES_NEW)

    小李录入数据库成功

    老钱录入数据库失败

    事务配置场景2
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0)
    @Transactional(propagation = Propagation.REQUIRES_NEW)

    小李录入数据库失败

    老钱录入数据库失败

    事务配置场景3
    异常放到propagation1  System.err.println(1/0)
    @Transactional(propagation = Propagation.REQUIRED)
     
    @Transactional(propagation = Propagation.REQUIRES_NEW)
     

    小李录入数据库失败

    老钱录入数据库成功

    5.NOT_SUPPORTED 非事务性执行,如果当前事务存在,则挂起当前事务

    方法名称 propagation1 propagation2 结果
    事务配置场景1
    
    
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0);
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
     

    小李录入数据库失败

    老钱录入数据库成功

    事务配置场景2  
    异常放到propagation1:System.err.println(1/0)
    @Transactional(propagation = Propagation.REQUIRED)
     
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
     

    小李录入数据库失败

    老钱录入数据库成功

    //场景1
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景2
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
            System.err.println(1/0);
        }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
        public void propagation2(){
            userMapper.insert("老钱",84);
    
        }
    View Code

    6.NEVER 以非事务方式执行,如果事务存在,则抛出异常

    方法名称 propagation1 propagation2 结果
    事务配置场景1 无事务
    异常放到propagation2:System.err.println(1/0);
    @Transactional(propagation = Propagation.NEVER)
     

    小李录入数据库成功

    老钱录入数据库成功

    事务配置场景2  
    @Transactional(propagation = Propagation.REQUIRED)
     
    @Transactional(propagation = Propagation.NEVER)
     

    小李录入数据库失败

    老钱录入数据库失败

    场景2会抛出异常: org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never' 

    //场景1
    public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
    @Transactional(propagation = Propagation.NEVER)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景2
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    
     @Transactional(propagation = Propagation.NEVER)
        public void propagation2(){
            userMapper.insert("老钱",84);
            //System.err.println(1/0);
        }
    View Code

     7.NESTED  如果当前事务存在,则在嵌套事务中执行

    //场景1
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
    
        }
    @Transactional(propagation = Propagation.NESTED)
        public void propagation2(){
            userMapper.insert("老钱",84);
            System.err.println(1/0);
        }
    View Code
    //场景2
    @Transactional(propagation = Propagation.REQUIRED)
        public void propagation1(){
    
            userMapper.insert("小李",44);
    
            service2.propagation2();
            System.err.println(1/0);
        }
    
    @Transactional(propagation = Propagation.NESTED)
        public void propagation2(){
            userMapper.insert("老钱",84);
    
        }
    View Code
    方法名称 propagation1 propagation2 结果
    事务配置场景1
    @Transactional(propagation = Propagation.REQUIRED)
    异常放到propagation2:System.err.println(1/0);
    @Transactional(propagation = Propagation.NESTED)
     

    小李录入数据库失败

    老钱录入数据库失败

    事务配置场景2  
    异常放到propagation1:System.err.println(1/0);
    @Transactional(propagation = Propagation.REQUIRED)
     
    @Transactional(propagation = Propagation.NESTED)
     

    小李录入数据库失败

    老钱录入数据库失败

     小结:

    嵌套事务:参考文章 https://blog.csdn.net/javashareauthor/article/details/82842177

    什么是嵌套事务?
           嵌套是子事务在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。
    
    可以通过下述的问答进一步去熟悉嵌套事务?
    1)如果子事务回滚,会发生什么? 
              父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。
    2)如果父事务回滚,会发生什么? 
              父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。
    3)事务的提交,是什么情况? 
              父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交
    作者:往霄龙
    求其上者得其中,求其中者得其下
  • 相关阅读:
    前端Tips#3
    前端Tips#2
    图算法
    【Javascript】重新绑定默认事件
    【Yeoman】热部署web前端开发环境
    添加远程链接MySQL的权限
    background-clip 背景图片做适当的裁剪
    linux系统下将php和mysql命令加入到环境变量中的方法
    background-size 设置背景图片的大小
    multiple backgrounds 多重背景
  • 原文地址:https://www.cnblogs.com/JQKA/p/11648022.html
Copyright © 2011-2022 走看看