spring的事务传播机制

前言:

Spring默认情况下会对运行期发生的异常(RunTimeException),即uncheck异常,进行事务回滚。如果遇到checked异常就不回滚。

不过也可以自定义:

1. 让checked也回滚:在整个方法前加上

@Transactional(rollbackFor=Exception.class)

2 .让unchecked不回滚:

@Transactional(notRollbackFor=RunTimeException.class)

3 .不需要事务管理的(只查询)方法:

@Transactional(propagation=Propagation.NOT_SUPPORTED)

正片:

在 spring的 TransactionDefinition接口中一共定义了六种事务传播属性:

TransactionDefinition中定义的->

Ⓐ :支持当前事务,如果当前没有事务

Ⓑ:以非事务方式执行操作,如果当前存在事务

样式:

甲方法{

       乙方法;

}

Required :Ⓐ, 新建。

注:甲有事务,乙就不再起新的事务。发生异常,一起回滚。

甲无事务,乙就会自己建一个,发生异常,甲回滚,乙不会

Supports :Ⓐ, 非事务。

注:甲有事务,乙不会再起新的事务。发生异常,一起回滚。

甲无事务,乙就以非事务执行,发生异常,也不会回滚。

Mandatory: Ⓐ, 抛异常。

注:甲有事务,乙不会再起新的事务。发生异常,一起回滚。

甲无事务,乙马上抛异常。

requires_NEW :新建事务,如果当前存在事务,把当前事务挂起。

注:甲有事务,乙会新建事务,将甲的事务挂起。发生异常,只有乙回滚。

当乙事务结束时,甲会继续有事务。

甲无事务,乙会新建事务。发生异常,只有乙回滚。

例:甲是required,乙是requires_NEW

甲和乙不会因为对方的执行情况而影响事务的结果, 因为它们根本就是两个事务

但注意一种情况。

如果乙已经提交,

如果乙抛出的异常未被甲的try-catch捕获,那么甲会回滚。

使用场景:一般日志记录行为不应影响主逻辑,可以用requires_NEW

日志服务的事务策略配置为propagation="REQUIRES_NEW",告诉Spring不管上下文是否有事务,Log Service被调用时都要求一个完全新的只属于Log Service自己的事务。通过该事务策略,Log Service可以独立的记录日志信息,不再受到业务逻辑事务的干扰。

NOT_supported :Ⓑ,挂起。

注:甲有事务,将甲挂起,乙以非事务执行,乙结束后,甲的事务继续。

甲无事务,乙以非事务执行。

Never :Ⓑ,抛异常。

注:甲只要有事务,就抛异常

甲无事务,乙以非事务执行。

下面的要求事务管理器支持事务嵌套行为。

在 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

Nested :如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与Required类似的操作。

例:甲是required,乙是requires_Nested

这时候乙是甲的事务的一部分

如果甲提交,乙也会被提交

如果甲回滚,乙也会被回滚

应用场景:

ServiceA {  

     //事务属性配置为 PROPAGATION_REQUIRED

    void methodA() {  

        try {  

            ServiceB.methodB();  

        } catch (SomeException) {  

            // 执行其他业务, 如 ServiceC.methodC();  

        }  

    }  

}  

这样会有分支执行的效果

1.如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(),

而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中。

2.当然methodA可以自由决定到底是提交还是回滚。

 

理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是:

PROPAGATION_REQUIRES_NEW 完全是一个新的事务,它与外部事务相互独立; 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back。

 

猜你喜欢

转载自blog.csdn.net/zhangyu672090/article/details/82828542