首先,事务的传播机制是Spring框架实现的功能,是java层面的概念。
事务的传播指的是,一个事务方法A,被另外一个方法B调用的时候,对方法A有何种影响(两个方法事务独立执行、A方法事务合并到B方法事务、或以非事务方式执行等)。
事务的传播机制仅限于不同类方法间相互调用,本文最后阐述。
传播机制 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
对7中传播特性逐一进行演示,为了不增加篇幅,采用伪代码方式演示
说明:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
演示1
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodM() {
insertTableA();
methodN();
insertTableA();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodN() {
insertTableB();
throw new RuntimeException();
}
结果1
A表、B表均插入失败。
methodM方法存在事务,methodN方法直接加入到methodM方法的事务中,所以methodN抛出异常,methodM方法回滚。
演示2
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodN() {
insertTableB();
throw new RuntimeException();
}
结果2
A表插入成功,B表插入失败。
methodM方法不存在事务,methodN方法新建一个事务。
说明:支持当前事务,如果当前没有事务,就以非事务方式执行。
演示
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.SUPPORTS)
public void methodN() {
insertTableB();
throw new RuntimeException();
}
结果
A表、B表均插入成功。
methodM方法没有事务,methodN则以非事务的方式运行。
说明:使用当前的事务,如果当前没有事务,就抛出异常。
演示
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.MANDATORY)
public void methodN() {
insertTableB();
}
结果
A表插入成功,B表插入失败。且methodN方法抛出异常。
methodM方法没有事务,methodN运行时则直接抛出异常。
说明:新建事务,如果当前存在事务,把当前事务挂起。
演示
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodM() {
insertTableA();
methodN();
throw new RuntimeException();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRES_NEW)
public void methodN() {
insertTableB();
}
结果
A表插入失败,B表插入成功。
methodN方法直接新建事务,methodM中抛出异常不影响methodN事务执行。
说明:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
演示
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.NOT_SUPPORTED)
public void methodN() {
insertTableB();
throw new RuntimeException();
}
结果
A表插入失败,B表插入成功。
methodN方法直接以非事务的方式运行。
说明:以非事务方式执行,如果当前存在事务,则抛出异常。
演示
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.NEVER)
public void methodN() {
insertTableB();
}
结果
A表、B表均插入失败。且methodN运行时抛出异常。
methodM方法存在事务,所以methodN运行时抛出异常,导致A表数据也插入不成功。
说明:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
演示
@Transactional(rollbackFor=Exception.class,propagation= Propagation.REQUIRED)
public void methodM() {
insertTableA();
methodN();
}
@Transactional(rollbackFor=Exception.class,propagation= Propagation.NESTED)
public void methodN() {
insertTableB();
}
结果
Spring声明式事务的实现原理默认采用动态代理的方式实现,在事务方法的前面动态切入开启事务的代码,在事务方法结束动态切入提交/回滚事务的代码。
事务的传播特性就是根据propagation属性配置的差异,在事务方法被调用时是否需要在本方法中切入 开始|提交|回滚 事务的代码。
因Spring声明式事务的实现原理为动态代理,所以事务的传播特性仅限于不同类方法间的相互调用,同类中事务方法被调用时,动态代理不生效,所以事务的传播也会失效。可通过上下文的方式注入类自身解决。