Spring-事务传播性

事务传播性

事务的传播性一般是在事务嵌套的时候使用,比如方法A是事务管理的,方法B也是有事务管理的,然后方法A中调用了方法B,那么这两个事务是各自作为独立的事务提交呢还是内层的事务合并到外层一起提交,这就是事务传播性要确定的问题.

场景

有如下两个方法

1
2
3
4
5
@Transactional
public void A(){
// ...
B();
}

1
2
3
4
@Transactional
public void B(){
// ...
}

PROPAGATION_REQUIRED

注解: @Transactional(propagation=Propagation.REQUIRED)

PROPAGATION_REQUIRED是Spring默认的事务传播机制,就是如果有外层事务的话,当前事务加到外层事务里面,一起提交一起回滚,基本可以满足大多数业务场景.

举例

以上面的场景为例,假设我们现在设置了事务的传播性@Transactional(propagation=Propagation.REQUIRED),然后A方法里面调用了B方法,所以B方法会加入A方法的事务,A和B两个方法同时提交,同时回滚.

这里要注意一点,在A方法里面调用B方法的时候加了try-catch,但是没有把异常抛出去,而B方法抛出了异常,那么整个事务也会回滚,这时候调用A方法的外层会收到Transaction rolled back because it has been marked as rollback-only的异常,而把B方法真正的异常吃掉了.

一般的话,在A,B两个方法中可以把异常抛出来,在调用A方法的时候再catch.

PROPAGATION_REQUIRES_NEW

注解: @Transactional(propagation=Propagation.REQUIRES_NEW)

PROPAGATION_REQUIRES_NEW这个传播机制是每次开启一个新的事务,同时把外层的事务挂起,当前事务执行完毕后,再恢复上层事务的执行

举例

以上面的场景为例,假设现在事务的传播方式设置的是@Transactional(propagation=Propagation.REQUIRES_NEW),首先调用A方法的时候会开启一个事务,然后A方法中调用B的时候会把A方法的事务挂起,然后再开启一个新的事务来执行B方法,执行完毕后再恢复A方法的事务.

然后呢有这样一个问题,如果B方法执行异常,回滚了,这时候A方法是否会回滚呢?
如果A方法中调用B的时候,加了try-catch,如果异常没有在catch中throw出来,那么A方法就不会回滚,这时候B方法的提交或回滚是对A方法没有影响的. 如果A方法中没有加try-catch,那么A方法也会回滚.

PROPAGATION_SUPPORTS

注解: @Transactional(propagation=Propagation.SUPPORTS)

PROPAGATION_SUPPORTS 该传播机制是如果外层有事务则加入到该事务中,如果不存在,也不会创建新事务,直接使用非事务方式执行

举例

以上面的场景为例,假设传播方式设置为@Transactional(propagation=Propagation.SUPPORTS),如果A方法的调用放没有开启事务的话,那么A,B两个方法都不会开启事务,因为外层是没有事务,也就不会创建,都是用非事务的执行方式了.

如果A方法的传播性是PROPAGATION_REQUIRED,B方法的传播性是PROPAGATION_SUPPORTS的时候,这时候外层的A方法会开启一个事务(或者说A的调用方有事务就加入该事务),然后B方法执行的时候会加入到A的事务中,同时提交同时回滚.

PROPAGATION_NOT_SUPPORTED

注解:@Transactional(propagation=Propagation.NOT_SUPPORTED)

PROPAGATION_NOT_SUPPORTED,该传播机制不支持事务,如果外层有事务的话,挂起外层事务,执行完毕后恢复.

举例

如果A方法的传播性是PROPAGATION_REQUIRED,B方法的传播性是PROPAGATION_NOT_SUPPORTED,首先A方法会开启一个事务(A外层有的话就加入进去),然后调用B方法的时候会挂起A的事务,然后执行B方法,执行完成之后再恢复A的事务.
无论B方法有没有抛出异常,B方法的事务都不会回滚,因为他不在事务的范围内, 那么A方法的事务呢?
如果A方法调用B的时候加了try-catch, 如果在执行过程中catch住的异常没有抛出去,那么就不会回滚,如果抛出去了,就回滚.

PROPAGATION_NEVER

注解:@Transactional(propagation=Propagation.NEVER)

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

PROPAGATION_MANDATORY

注解:@Transactional(propagation=Propagation.MANDATORY)

PROPAGATION_MANDATORY,该传播机制是只能在已存在事务的方法中调用,如果在没有事务的方法中调用的话,抛出异常IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");

PROPAGATION_NESTED

注解:@Transactional(propagation=Propagation.NESTED)

PROPAGATION_NESTED该传播机制特点是可以保存状态保存点,当事务回滚后,会回滚到某一个保存点上,从而避免所有嵌套事务都回滚.

举例

假设上面A,B方法传播性都设置为:@Transactional(propagation=Propagation.NESTED),如果B方法抛出异常,两个方法还是都会回滚,因为B方法虽然回滚到了savePoint,而savePoint里面确实包含了A方法的操作,但是savePoint还是会把异常throw给A,这就导致了A的回滚.

总结

  • PROPAGATION_REQUIRED:有外层事务就加到外层事务,一起提交回滚.
  • PROPAGATION_REQUIRES_NEW:新开一个事务,挂起外层事务,执行完毕后再恢复外层事务.
  • PROPAGATION_SUPPORTS:外层有事务的话就加进去,没有的话就用非事务的方式执行.
  • PROPAGATION_NOT_SUPPORTED:外层有事务的话,就挂起,然后以非事务的方式执行,执行完毕后恢复外层事务.
  • PROPAGATION_NEVER:不支持事务,外层有事务的话就报错.
  • PROPAGATION_MANDATORY: 外层没有事务的话,就报错.
  • PROPAGATION_NESTED: 可以回滚到savePoint上.