Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,本文将介绍Spring的7种事务传播机制。
1. PROPAGATION_REQUIRED
默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。如下图:
在调用userService对象的save方法时,此方法用的是Required传播行为且此时Spring事务管理器发现还没开启逻辑事务,因此Spring管理器开启逻辑事务;
在此逻辑事务中调用了addressService对象的save方法,而在save方法中发现同样用的是Required传播行为,因此使用该已经存在的逻辑事务;
在返回到addressService对象的save方法,当事务模板类执行完毕,此时提交并关闭事务。
由于userService对象的save方法和addressService的save方法属于同一个物理事务,如果发生回滚,则两者都回滚。
2. PROPAGATION_REQUIRES_NEW
每次都创建一个新事务(包括物理事务),该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。如下图:
当执行userService对象的save方法时,由于传播行为是RequiresNew,因此创建一个新的逻辑事务(物理事务也是不同的);
当执行到addressService对象的save方法时,由于传播行为是RequiresNew,因此首先暂停上一个逻辑事务并创建一个新的逻辑事务(物理事务也是不同的);
addressService对象的save方法执行完毕后,提交逻辑事务(并提交物理事务)并重新恢复上一个逻辑事务,继续执行userService对象的save方法内的操作;
最后userService对象的save方法执行完毕,提交逻辑事务(并提交物理事务);
userService对象的save方法和addressService对象的save方法不属于同一个逻辑事务且也不属于同一个物理事务。
3. PROPAGATION_SUPPORTS
该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。如下图:
4. PROPAGATION_NOT_SUPPORTED
不支持事务,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,即以非事务方式执行;如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行,结束后恢复上下文的事务。如下图:
5. PROPAGATION_MANDATORY
该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。如下图:
6. PROPAGATION_NEVER
PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行。如下图:
7. PROPAGATION_NESTED
嵌套事务支持。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。如下图:
Nested和RequiresNew的区别:
RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;
Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;
Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务。
使用嵌套事务,必须确保具体事务管理器实现的nestedTransactionAllowed属性为true,否则不支持嵌套事务,如DataSourceTransactionManager默认支持,而HibernateTransactionManager默认不支持,需要我们来开启。