前言
当我们调用一个基于Spring的Service接口方法时,它将运行于Spring管理的事务环境中,Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作,因此就会产生服务接口方法嵌套调用的情况, Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。
事务传播是Spring进行事务管理的重要概念,其重要性怎么强调都不为过。但是事务传播行为也是被误解最多的地方,在本文里,我们将详细分析不同事务传播行为的表现形式,掌握它们之间的区别。
注:本文可以与上篇文章一同参考
MySQL事务的四个隔离级别详解
Spring的事务传播行为
- PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
- PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
注意:
1、开启PROPAGATION_NESTED传播行为时,需要开启nestedTransactionAllowed属性为true。
即支持事务的savepoint操作。
2、nestedTransactionAllowed默认为false。
3、JDK要在1.4+
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
<!-- 开启 PROPAGATION_NESTED 事务传播行为 -->
<property name="nestedTransactionAllowed" value="true"/>
</bean>
下面提一些基本知识
- 事务传播机制只适用于不同bean之间方法的调用,如果一个bean中的两个方法互相调用并不会使用到事务传播。
- 事务方法里如果抛RuntimeException,则会导致所有相关事务回滚,个别事务传播机制有点特殊,我们下面会讲到。
- 事务方法里如果抛Throwable或者Exception,默认不会导致相关事务回滚,一般都会在出异常的地方提交,就有可能出现部分提交的问题。但可以配置rollback-for属性来控制。
下面我们来详细看一下七个Spring事务传播行为
@Service
public class BaseServiceImpl implements BaseService {
@Autowired
private BaseHibernateDao baseHibernateDao;
@Autowired
private LoginService loginService;
//外部事务
@Override
@Transactional(propagation = Propagation.REQUIRED)
public Serializable save1(LoginUser entity) throws Exception {
Serializable save = null;
loginService.save2(new LoginUser());
return save;
}
}
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private BaseHibernateDao baseHibernateDao;
//内部事务
@Override
@Transactional
public Serializable save2(LoginUser entity) throws Exception {
Serializable save = null;
entity.s