Spring事务传播
Spring 事务传播性是指当多个含有事务的方法嵌套调用时,这多个方法处理事务的规则。如下图所示,事务方法之间调用,如何处理之间的事务。
事务传播方式
-
PROPAGATION_REQUIRED
这个传播行为是 Spring 默认的事务传播行为,它指的是如果外层调用方法已经开启了事务,那么当前方法就加入到外层事务。如果外层调用方没有开启事务,那么当前方法就开启一个事务。
-
PROPAGATION_REQUIRES_NEW
这个传播行为是每次都新开启一个事务。如果外层调用方已经开启了事务,就先把外层的事务挂起,然后执行当前新事务,执行完毕后再恢复上层事务的执行。
-
PROPAGATION_SUPPORTS
这个传播行为是指,如果外层调用方开启了事务,那当前方法加入到外层事务。如果外层不存在事务,那么当前方法也不会创建新事务,直接使用非事务方式执行。
-
PROPAGATION_NOT_SUPPORTED
这个传播行为不支持事务。也就是如果外层调用者开启了事务,就挂起外层事务 ,然后以非事务方式执行当前方法逻辑,等执行完毕后,再恢复外层事务的执行。
-
PROPAGATION_NEVER
这个传播行为不支持事务。也就是说如果外层调用者开启了事务,就执行当前方法前会抛出异常。
-
PROPAGATION_MANDATORY
这个传播行为是说,配置了这个传播性的方法只能在已经存在事务的方法中被调用。如果在不存在事务的方法中被调用,会抛出异常。
-
PROPAGATION_NESTED
当外层调用方存在事务时,当前方法合并到外层事务,如果外层不存在事务,就当前开启事务,这点和 PROPAGATION_REQUIRED 传播性一致,不同的是,PROPAGATION_NESTED传播行为的特点是可以保存状态保存点,当事务回滚时,可以回滚到某一个保存点上,从而避免所有嵌套事务都回滚。
PROPAGATION_REQUIRED
这个传播行为是 Spring 默认的事务传播行为,它指的是如果外层调用方法已经开启了事务,那么当前方法就加入到外层事务。如果外层调用方没有开启事务,那么当前方法就开启一个事务。
例
@Service
@Slf4j
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodA1() {
//1.1做自己的入库操作
insert();
log.info("save something to db");
//1.2调用服务B的入库操作
try{
serviceB.methodB1();
}catch (Exception e){
log.error("B异常了");
}
}
}
@Service
@Slf4j
public class ServiceB {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodB1() {
insert();
log.info("save something to db");
//抛出异常
//throw new RuntimeException();
}
}
private void insert(){
String sql = "insert into users(name) values(?)";
int count = jdbcTemplate.update(sql,"郭靖");
log.info("新增条数:{}",count);
}
当事务方法A对事务方法B捕获异常并处理,并没有将异常抛出当前事务A之外,则事务A会提交。若没有捕获则事务A会进行回退。
PROPAGATION_REQUIRES_NEW
这个传播行为是每次都新开启一个事务。如果外层调用方已经开启了事务,就先把外层的事务挂起,然后执行当前新事务,执行完毕后再恢复上层事务的执行。
先开启事务A,然后执行方法A。
调用方法B前,挂起事务A,开启事务B,执行方法B。
此时方法B抛出异常,会回退事务B。
重新进入事务A,若异常被捕获,则提交事务A,若无,则回退事务A.
@Service
@Slf4j
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodA1() {
//1.1做自己的入库操作
insert();
log.info("save something to db");
//1.2调用服务B的入库操作
try{
serviceB.methodB1();
}catch (Exception e){
log.error("B异常了");
}
}
}
@Service
@Slf4j
public class ServiceB {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED_NEW)
public void methodB1() {
insert();
log.info("save something to db");
//抛出异常
throw new RuntimeException();
}
}
// 结果:插入了一条数据
PROPAGATION_SUPPORTS
这个传播行为是指,如果外层调用方开启了事务,那当前方法加入到外层事务。如果外层不存在事务,那么当前方法也不会创建新事务,直接使用非事务方式执行。
例(1)外层方法A有事务
@Service
@Slf4j
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void methodA3_1() {
//1.1做自己的入库操作
insert();
log.info("save something to db");
//1.2调用服务B的入库操作
try{
serviceB.methodB3_1();
}catch (Exception e){
log.error("B异常了");
}
}
}
@Service
@Slf4j
public class ServiceB {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
public void methodB3_1() {
insert();
log.info("save something to db");
//抛出异常
throw new RuntimeException();
}
}
结果:无结果插入
INFO 6764 --- [ main] com.example.demo.service.ServiceA : 新增条数:1
INFO 6764 --- [ main] com.example.demo.service.ServiceA : save something to db
INFO 6764 --- [ main] com.example.demo.service.ServiceB : 新增条数:1
INFO 6764 --- [ main] com.example.demo.service.ServiceB : save something to db
ERROR 6764 --- [ main] com.example.demo.service.ServiceA : B异常了
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
(2)外层无事务
结果:两条结果都插入
INFO 6764 --- [ main] com.example.demo.service.ServiceA : 新增条数:1
INFO 6764 --- [ main] com.example.demo.service.ServiceA : save something to db
INFO 6764 --- [ main] com.example.demo.service.ServiceB : 新增条数:1
INFO 6764 --- [ main] com.example.demo.service.ServiceB : save something to db
ERROR 6764 --- [ main] com.example.demo.service.ServiceA : B异常了
PROPAGATION_NOT_SUPPORTED
这个传播行为不支持事务。也就是如果外层调用者开启了事务,就挂起外层事务 ,然后以非事务方式执行当前方法逻辑,等执行完毕后,再恢复外层事务的执行。
PROPAGATION_NEVER
这个传播行为不支持事务。也就是说如果外层调用者开启了事务,就执行当前方法前会抛出异常。
PROPAGATION_MANDATORY
这个传播行为是说,配置了这个传播性的方法只能在已经存在事务的方法中被调用。如果在不存在事务的方法中被调用,会抛出异常。
PROPAGATION_NESTED
当外层调用方存在事务时,当前方法合并到外层事务,如果外层不存在事务,就当前开启事务,这点和 PROPAGATION_REQUIRED 传播性一致,不同的是,PROPAGATION_NESTED传播行为的特点是可以保存状态保存点,当事务回滚时,可以回滚到某一个保存点上,从而避免所有嵌套事务都回滚。