文章目录
场景一:事务方法内部捕捉了异常,但是没有抛出异常,导致事务操作不会进行回滚。
示例代码如下:
@Transactional(rollbackFor = Exception.class)
public void function() {
try {
testMapper.insertOne();
testMapper.insertTwo();
}catch (Exception e){
//如果此时有异常,而没有抛,事务失效,不会回滚
e.printStackTrace();
//正常抛出时,事务不失效,回滚
throw e;
}
}
场景二: 在类内部调用类内部@Transactional标注的方法。
这种情况下也会导致事务不开启,比如有一个类Test,它的一个方法A,A再调用本类的方法B,则外部调用方法A之后,方法B的事务是不会起作用的。
原因分析:由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
既然事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。
public void deleteUser() throws MyException{
deleteUser2();
}
@Transactional
public void deleteUser2() throws MyException{
userMapper.deleteUserA();
int i = 1 / 0;
userMapper.deleteUserB();
}
解决方式:
把当前类自己注入一下调用即可。(或者第一个方法deleteUser加注解,1、如果A加了@Transaction注解,B上有没有@Transaction注解,事务都是有效的,则AB在同一个事务中。)
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
//自己注入自己
@Autowired
UserService userService;
public void deleteUser() throws MyException{
userService.deleteUser2();
}
@Transactional
public void deleteUser2() throws MyException{
userMapper.deleteUserA();
int i = 1 / 0;
userMapper.deleteUserB();
}
}
场景三: 抛出非运行异常RuntimeException,且没有指定rollbackFor=异常类型
@Transactional
public void deleteUser() throws MyException{
userMapper.deleteUserA();
try {
int i = 1 / 0;
userMapper.deleteUserB();
} catch (Exception e) {
throw new MyException();
}
}
解决方式:
如果指定了回滚异常类型为Exception,那么就可以回滚非RuntimeException类型异常了。
@Transactional(rollbackFor = Exception.class)
总结一下
@Transactional只能回滚RuntimeException和RuntimeException下面的子类抛出的异常 不能回滚Exception异常
如果需要支持回滚Exception异常请用@Transactional(rollbackFor = Exception.class)
这里如果是增删改的时候我建议大家都使用@Transactional(rollbackFor = Exception.class)