声明式事务--调用链上游方法如不开启事务需避坑
新建一个springboot项目进行事务测试,加入jpa依赖,创建数据库test,新增表User,就三个字段id,username,password.
测试1:同一个类中,加了@Transactional注解的方法调用没加注解的方法
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Transactional
@Override
public void add(){
addActually();
}
private void addActually(){
User user = new User(1,"zhangsan","pwd");
userRepository.save(user);
throw new RuntimeException();
}
}
测试结果:不论在哪个方法中抛出异常,事务都能正常回滚。
测试二:同一个类中,未加注解的方法调用加了@Transactional注解的方法
@Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Override public void add(){ addActually(); } @Transactional(propagation = Propagation.MANDATORY) public void addActually(){ User user = new User(1,"zhangsan","pwd"); userRepository.save(user); throw new RuntimeException(); } }
测试结果:无论在哪个方法中抛出异常,事务都没有回滚。
这里我特意说明了事务的传播特性为MANDATORY,用于测试这里@Transactional注解是否生效,结果是还是抛出我显示编码的RuntimeException,而不是IllegalTransactionStateException。
说明addActually()方法的@Transactional注解完全被忽略了。
测试3:类A的未加事务注解的方法调用类B的加了@Transactional注解的方法
@Service public class UserServiceImpl implements UserService { @Autowired private CopiedUserService copiedUserService; @Override public void add(){ copiedUserService.addActually(); } } @Service public class CopiedUserServiceImpl implements CopiedUserService { @Autowired private UserRepository userRepository; @Transactional @Override public void addActually(){ User user = new User(1,"zhangsan","pwd"); userRepository.save(user); throw new RuntimeException(); } }
测试结果:事务正常回滚。
结论:为所有需要开启事务的方法及同一个类中上游调用方法都开启事务。
编程式事务或不在同一个类中无需这么做,猜想这是与aop的代理机制相关的。下次再继续分析。