spring事务之传播性

550 阅读4分钟

一、事务传播性

什么是事务的传播性 事务的传播性一般在事务嵌套时候使用,比如在事务A里面调用了另外一个使用事务的方法,那么这俩个事务是各自作为独立的事务执行提交,还是内层的事务合并到外层的事务一块提交那,这就是事务传播性要确定的问题。下面一一介绍比较常用的事务传播性。

1.1 PROPAGATION_REQUIRED(同一个事务)

Spring默认的事务传播机制,如果外层有事务则当前事务加入到外层事务,一块提交一块回滚,如果外层没有事务则当前开启一个新事务。这个机制可以满足大多数业务场景。 示例:

public class ServiceA {
    @Autowired
    private ServiceB serviceB;
    public void testA(){
        serviceB.testB();
    }
}
public class ServiceB {
    public voic testB(){
        ......
    }
}

ServiceA 和ServiceB都是进行过事务增强后的,那么在执行testA的时候会开启一个事务,执行到testB()时候由于传播性是PROPAGATION_REQUIRED,所以testB方法加入到testA的事务(同一个事务里),那么testB和testA就会同时提交,同时回滚。值得注意的是如果testA里面调用testB时候加了trycatch没有把异常跑出去,而testB方法却抛出了异常,那么整个事务也会回滚,这时候调用testA的外层会受到"Transaction rolled back because it has been marked as rollback-only的异常,而把testB真正的异常吃掉了。平时我们service层不应该catch掉异常,而应该抛出来,让调用方catch异常。

1.2 PROPAGATION_REQUIRES_NEW(两个不同的事务)

该传播机制是每次新开启一个事务,同时把外层的事务挂起,当前新事务执行完毕后在恢复上层事务的执行。 以上面代码为例,首先进入testA方法前会开启一个事务,然后调用testB时候会把testA的事务挂起,从新开启一个新事务执行testB,执行完毕后恢复testA的事务。如果testB抛出来异常则testB的事务会回滚,那么testA方法是否回滚?这个要看情况,如果test在调用sayHello 时候使用了trycatch并且异常没有在catch中throw出来,那么testA方法不会回滚,这时候testB是提交和回滚对testA没有影响,。 如果testA中没有加trycatch那么,testA也会回滚。

1.3 PROPAGATION_SUPPORTS(可有可无)

该传播机制如果外层有事务则加入该事务,如果不存在也不会创建新事务,直接使用非事务方式执行。 以上面代码为例,由于PROPAGATION_SUPPORTS,所以testA和testB都没有开启事务,没啥好讲的。 如果testA传播性是PROPAGATION_REQUIRED,testB传播性是PROPAGATION_SUPPORTS的情况。这时候外层testA会开启一个事务,然后testB执行时候会加入到test的事务和1.1类似,(也是同一个事务)同时提交同时回滚。

1.4 PROPAGATION_NOT_SUPPORTED(不支持事务)

该传播机制不支持事务,如果外层存在事务则挂起外层事务 ,然后执行当前逻辑,执行完毕后,恢复外层事务。 同样这里看下如果testA使用PROPAGATION_REQUIRED,testB传播性是PROPAGATION_NOT_SUPPORTED的情况,首先testA会开启一个事务,然后testB执行时候会挂起该事务然后在非事务内做自己的事情,做完后在恢复testA的事务。 无论testB是否抛出异常,testB的事务都不会回滚,因为它不在事务范围内,那testA就和1.2一样了,如果test catch住sayHello的异常没有throw出去,那么test就不回滚,否者回滚。

1.5 PROPAGATION_NEVER

该传播机制不支持事务,如果外层存在事务则直接抛出异常。 IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation 'never'")

1.6 PROPAGATION_MANDATORY

该传播机制是说配置了该传播性的方法只能在已经存在事务的方法中被调用,如果在不存在事务的方法中被调用,会抛出异常。(调用者必须是事务,否则报错) IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'");

1.7 PROPAGATION_NESTED

它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交或回滚. 也就是外部事务提交子事务才能commit,外部事务回滚子事务也回滚 如果内部事务回滚将不影响外部事务,内部事务回滚时只回滚到savepoint,当然内部事务可以通过回滚手动抛出异常影响外部事务(业务需求而定)。 其用法和1.1的PROPAGATION_REQUIRED几乎一样,最大的不同是此情景下如果testA调用testB时trycatch了,而testB抛异常了,testA是不会回滚和抛异常的。

总结,只有传播性为PROPAGATION_REQUIRED||PROPAGATION_REQUIRES_NEW||PROPAGATION_NESTED时候才可能开启一个新事务。