例子:对于默认的传播级别 REQUIRED 的测试
首先对于 REQUIRED 的解释如下: 默认事务类型,如果没有,就新建一个事务;如果有,就加入当前事务,也就是大家都使用同一个事务模型,只要有一个发生了异常,那么整个事务都会回滚。
其中对于发生异常导致事务回滚需要注重理解,否则对于REQUIRES_NEW 就会认为某些行为与预先的不一样。
下面针对 REQUIRES_NEW 的测试如下:
@Service
public class A {
@Resource
private PersonMapper personMapper;
@Resource
private B b;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save() {
personMapper.insert(Person.builder().name("A").age(12).build());
b.save();
}
}
@Service
public class B {
@Resource
private PersonMapper personMapper;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save() {
personMapper.insert(Person.builder().name("B").age(12).build());
throw new RuntimeException();
}
}
@GetMapping(value = "/get2")
public Object get2() {
a.save();
return "success";
}
由于最开始对于异常回滚理解错误,认为在调用A的save()方法时,创建一个事务,这时再在 调用 b的save() 由于传播级别是创建新的事务,所以B抛出异常,应该仅仅会导致B的保存失败,但是实际测试却发现,A,B的保存都失败了,经过仔细的思考,认为,事务重新创建应该是没有问题的,可能是对于异常回滚的理解错误导致的。
于是修改了A 如下:
@Service
public class A {
@Resource
private PersonMapper personMapper;
@Resource
private B b;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save() {
personMapper.insert(Person.builder().name("A").age(12).build());
try{
b.save();
}catch (Exception e){
}
}
}
经过测试,发现此时就是 B保存失败而A保存成功了,经过测试推论如下:
在A对象中没有追加try catch的时候,当B 抛出异常的时候,B的事务回滚,但是由于并没有对该异常进行处理,于是该异常扩散到了A中的调用点(b.save();)由于此处的异常,因而导致A回滚了,当追加 try catch 之后 此异常就不会导致A回滚了。
为了验证此猜想,编写如下测试用例:
@Service
public class A {
@Resource
private PersonMapper personMapper;
@Resource
private B b;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void save() {
personMapper.insert(Person.builder().name("A").age(12).build());
try{
b.save();
}catch (Exception e){
}
}
}
@Service
public class B {
@Resource
private PersonMapper personMapper;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void save() {
personMapper.insert(Person.builder().name("B").age(12).build());
throw new RuntimeException();
}
}
在进行测试,就发现事务回滚了,表明B中的异常导致了整个事务的回滚。
下面继续测试嵌套事务 NESTED :嵌套事务 类似于后一个事务为第一个事务的子事务
经过测试规则如下:父事务回滚,子事务一定回滚,但是子事务回滚,不影响父事务回滚。
PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行;如果有,就使用当前事务。
以下的事务就比较容易理解了:
PROPAGATION_NOT_SUPPORTED:如果没有,就以非事务方式执行;如果有,就将当前事务挂起。即无论如何不支持事务。
PROPAGATION_NEVER:如果没有,就以非事务方式执行;如果有,就抛出异常。
PROPAGATION_MANDATORY:如果没有,就抛出异常;如果有,就使用当前事务。