spring 七种事务传播行为

spring事务传播行为详解

  • 前言
    Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为。这是Spring为我们提供的强大的工具箱,使用事务传播行可以为我们的开发工作提供许多便利。但是人们对他的误解也颇多,你一定也听过“service方法事务最好不要嵌套”的传言。要想正确的使用工具首先需要了解工具。

一、什么是事务传播行为?

事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。

用伪代码说明:

public void methodA(){
    methodB();
    //doSomething
 }
 
 @Transaction(Propagation=XXX)
 public void methodB(){
    //doSomething
 }

代码中methodA()方法嵌套调用了methodB()方法,methodB()的事务传播行为由@Transaction(Propagation=XXX)设置决定。这里需要注意的是methodA()并没有开启事务,某一个事务传播行为修饰的方法并不是必须要在开启事务的外围方法中调用。

二、Spring中七种事务传播行为

事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 注意:REQUIRED方法内的事务方法,不应该try-catch 而不抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。 注意:完全是新的事务,回滚或提交不受外部影响。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 注意:NESTED方法抛出异常被回滚,不会影响到外围方法的事务;但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。 注意:最好不要用这个,因为加了和不加是一个效果
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。

定义非常简单,也很好理解,下面我们就进入代码测试部分,验证我们的理解是否正确。

三、REQUIRED,REQUIRES_NEW,NESTED异同

NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。

NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务。

四、三种Transactional不回滚问题

  • 1.检查你方法是不是public的,public方法的Transactional注解才是有效的,才能控制事务。

  • 2.Spring默认只对UnChecked异常(RuntimeException)回滚,对于Checked(Exception)异常不回滚。

你的异常类型是Checked异常。如果想check异常也想回滚怎么办?

(1)注解上加rollbackFor=Exception.class

(2)对异常进行转换,转换成RuntimeException或自定义继承RuntimeException的异常

  • 3.同一个类中的方法调用,内部方法的事务是没有效果。


如方法A没加事务,方法B中加了事务(不管加的是什么类型的事务)。方法A调用方法B,这样方法B中的事务是无效的。因为AOP只对A方法进行处理了,而不会对内部的B方法进行处理。

五、异常:Transaction rolled back because it has been marked as rollback-only原因

  • 1.捕获后又抛出了不回滚的异常(默认RuntimeException才回滚,而Exception不回滚)。

  • 2.Propagation.REQUIRED A方法调用 Propagation.REQUIRED B方法,如果捕获了B方法中的异常没有抛出 或 捕获后又抛出了不回滚的异常(默认Exception不回滚)。

引用:

https://segmentfault.com/a/1190000013341344

https://www.cnblogs.com/caoshouling/p/8644711.html

猜你喜欢

转载自blog.csdn.net/godloveleo9527/article/details/108821898
今日推荐