一、REQUIRED
(当前存在事务就用当前,没有就创建新的事务)
当前方法必须在Transaction中运行,支持当前已经存在的事务,如果还没有事务,就创建一个新事务。这是默认值,也即不进行该参数配置等于配置成REQUIRED。
Class A {
@Transactional(propagation=propagation.REQUIRED)
public void funA {
B b = new B();
b.funB();
}
}
Class B {
@Transactional(propagation=propagation.REQUIRED)
public void funB {
// doSomeThing
}
}
purchase代表两个声明了事务的方法,并且传播行为是系统的默认行为。同时checkout也是一个声明了事务的方法,在该方法中调用前述的两个方法。当checkout执行到第一个方法的时候,第一个方法继续使用checkout的事务进行执行,第二个方法一样,所以整个方法只有一个事务。
对于这样的配置,如果funB过程中发生异常需要回滚,那么funA中所进行的所有数据库操作也将同时被回滚,因为这两个方法使用了同一个事务。
二、REQUIRES_NEW
(无论如何创建一个新的事务)
当前方法必须运行在它自己的事务中。一个新的事务将被启动,如果存在当前事务,在该方法执行期间,当前事务会被挂起(如果一个事务已经存在,则先将这个存在的事务挂起)。
如果一个事务发生了错误,那么回滚。所以REQUIRED属性中,如果第二个方法发生错误,第一个方法也会回滚,然而REQUIRES_NEW属性中,第二个方法发生错误,因为第一个是单独的事务,所以不会受到影响。
那么,如果两个混合使用呢?
(为简单起见,REQUIRED在下述表达称为系统默认,REQUIRES_NEW称为new)
现在测试第一种方法的属性为系统默认,第二种方法为new,第二种方法出现错误。此时结果是方法1也回滚。但是按照前面的理解,方法2是单独的事务,应该只造成自己回滚,为什么第一种方法也会回滚?
第一种方法发生错误后,产生错误造成本身回滚,但是他的异常因为没有捕获,所以传到了主方法的事务中,主方法的事务出现错误,所以回滚,第一个方法在主方法的事务中,所以第一个方法的SQL语句会回滚!
如果第一种方法为new,第二种方法为系统默认,那么第二种发生错误后,主方法的事务回滚,然后第一种方法是自己的事务,所以不受影响,不会回滚,第一个方法的SQL语句就会执行。
三、SUPPORTS
(支持事务)
当前方法不需要在Transaction中运行,如果存在已经定义的Transaction,且该方法在定义的事务范围内被调用,则该方法也可以在事务中正常执行。如果方法在事务范围外被调用,该方法就在没有事务的环境下执行。
四、NOT_SUPPORTED
(不支持事务)
声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
五、NEVER
该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。
六、MANDATORY
(强制性的)
支持当前已经存在的事务,如果还没有事务,就抛出一个异常。该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出异常。
Class A {
@Transactional(propagation=propagation.MANDATORY)
public void funA {
B b = new B();
b.funB();
}
}
Class B {
@Transactional(propagation=propagation.REQUIRED)
public void funB {
// doSomeThing
}
}
七、NESTED
(嵌套)
外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与REQUIRED一样。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。
@Transactional(rollbackFor=Exception.class)
public String a() {
this.bSerivce..b();
dosomething...
}
@Transactional(propagation = Propagation.NESTED)
public void b(){
dosomething...
}