PPXu

图解Spring事务传播类型

2019-03-19

Spring事务传播机制

Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的。

下面以a.save()里调用了b.save()举例,事务方法之间调用时事务如何传播。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class A {

@Autowired
private B b;

@Transactional(propagation=Propagation.XXX)
public void save() {
// ...
b.save();
// ...
}
}
1
2
3
4
5
6
7
8
@Service
public class B {

@Transactional(propagation=Propagation.XXX)
public void save() {
// ...
}
}

1. REQUIRED

默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。如下图:

由于两个方法属于同一个物理事务,如果发生回滚,则两者都回滚。

2. SUPPORTS

顾名思义就是可以支持事务,如果b.save()在事务环境中运行,则以事务形式运行,否则以非事务运行。

注:这里所谓的非事务形式的数据库访问只是指没有显式的事务边界而已,就是说数据库操作只是 auto-commit 的方式,在数据库的物理事务概念上,还是有事务的。譬如在这里,a.save()调用b.save(),如果当a是非事务执行(非手动提交事务,而是auto-commit),那么b.save()在执行前,a.save()的物理事务就要先提交,而同时,b.save()的物理事务也是auto-commit,这样才是这里说的b.save()以非事务方法运行,而不是指b.save()不开启数据库物理事务。而所谓的b.save()在事务环境中运行,是指当b的外层a.save()本身是手动提交事务时,b.save()也会包含在a.save()里边的同一个事务去执行,也就是说a.save()与b.save()的SQL操作在同一个物理事务中。

3. MANDATORY

必须在一个事务中运行,也就是说,b.save()只能在已有事务的方法中被调用,否则会抛异常。

4. REQUIRES_NEW

总是会创建一个新事务(包括物理事务),该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。如下图:

两个方法之间既不属于同一个逻辑事务也不属于同一个物理事务。

5. NOT_SUPPORTED

顾名思义不支持事务,当处于存在事务的上下文环境中运行时,b.save()会暂停当前已开启的事务,意味着a.save()的事务被挂起直至b.save()以非事务方法运行完毕后,a.save()的事务继续执行。

6. NEVER

绝不能在事务环境中运行,如果a.save()里声明了使用事务,而b.save()的事务类型声明为never,那么只能以抛异常告终。

与Mandatory相反,Mandatory意思是强制要求上下文中有事务(外层有事务),否则抛异常,而Never是上下文中不能有事务(外层无事务),否则抛异常。

7. NESTED

嵌套事务支持。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。

Nested和RequiresNew的区别:

  • RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而RequiresNew由于都是全新的事务,所以之间是无关联的
  • Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务

    使用嵌套事务,必须确保具体事务管理器实现的nestedTransactionAllowed属性为true,否则不支持嵌套事务,如DataSourceTransactionManager默认支持,而HibernateTransactionManager默认不支持,需要我们来开启。

扫描二维码,分享此文章