事务分析(二) 事务传播

事务传播分析 @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)事务的提交,是什么情况? 
          父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交
作者:往霄龙
求其上者得其中,求其中者得其下
原文地址:https://www.cnblogs.com/JQKA/p/11648022.html