0. 引言
有同学遇到设置了事务,但是也报出了错误,但是一致未生效的问题,事务没有回滚,rollbackFor也设置成了捕捉全部报错Exception,那么这是怎么回事呢,其实原因很简单
1. 问题分析
首先我们要知道,事务的回滚是通过捕捉到错误了才执行的,如果本身没有报错是肯定不会进行回滚的。但还有一种情况,是大家比较容易忽略的,比如如下的一段代码,你觉得保存数据的操作会回滚吗?
@Transactional(rollbackFor = Exception.class)
public R save2(UserVO userVO) {
User user = new User();
// 拷贝属性
BeanUtils.copyProperties(userVO, user);
try {
// 保存数据库
saveUser(user);
// 除数为0,将会报错
int i = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
return R.fail("操作失败");
}
return R.success("操作成功");
}
答案是不会,为什么呢?因为你并没有将错误抛出,而是选择了catch,也就是自己处理报错,因此@Transactional
自然捕捉不到报错,也就不会进行回滚了
我们可以更简单的将try,catch去除掉,让@Transactional
捕捉到错误,定义一个全局的错误拦截器处理报错返回即可。
@Transactional(rollbackFor = Exception.class)
public R save2(UserVO userVO) {
User user = new User();
// 拷贝属性
BeanUtils.copyProperties(userVO, user);
// 保存数据库
saveUser(user);
// 除数为0,将会报错
int i = 1 / 0;
return R.success("操作成功");
}
当然,如果你实在需要手动的try,catch,可能你还需要在catch里实现一些自定义的操作, 那么这时候怎么办呢?
@Transactional
也提供了手动进行事务回滚的方法:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
于是我们的代码就可以调整为
@Transactional(rollbackFor = Exception.class)
public R save2(UserVO userVO) {
User user = new User();
// 拷贝属性
BeanUtils.copyProperties(userVO, user);
try {
// 保存数据库
saveUser(user);
// 除数为0,将会报错
int i = 1 / 0;
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();
return R.fail("操作失败");
}
return R.success("操作成功");
}
2. 其他事务未生效的场景
- final、static 修饰的方法或者类不支持
@Transactional
- 非public 修饰的方法不支持
@Transactional
- 当前类不是bean,或者没有被spring容器管理
- 数据库不支持事务
- 事务的传播机制导致