在项目中 @service层中 我们会经常在做一些增删改操作的方法上看到 spring 的事务注解 @Transactional已知@Transactional 是让spring 帮我们实现事务的控制。
但是在项目中会经常看到 有的方法中 会存在trycatch块包括的方法上注解 @Transactional
@Override
@Transactional
public int add(AddReq aAddReq) {
try{
} catch (Exception e) {
.....
e.printStackTrace();}
return 1;
}
上述的方法执行后可以看到事务并没有执行,再看一个例子:
@Override
@Transactional
public int addOrder(AddReq aAddReq) {
try{
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();}
return 1;
}
上述方法执行后我们可以看到事务最后执行了,但实际上 事务 执行只是因为手动硬编码开启spring事务管理起了作用 而方法上的注解并没有起作用
接下来再看一个例子:
@Override
@Transactional
public int addOrder(AddReq aAddReq) {
try{
} catch (Exception e) {
throw new RuntimeException();
}
return 1;
}
上述方法执行后我们可以看到事务是执行了的,但这里有个小细节:@Transactional不做任何配置 默认是对抛出的unchecked异常回滚,checked异常不会回滚,为了让所有异常都会让事务启动可以将 @Transactional配置为 @Transactional(rollbackFor = Exception.class)
解释:
spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(spring默认取决于是否抛出runtime异常). 如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。 一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
Spring 事务注解 @Transactional 本来可以保证原子性,如果事务内有报错的话,整个事务可以保证回滚,但是加上try catch或者事务嵌套,可能会导致事务回滚失败。 针对trycatch与@Transactional嵌套使用的结论总结如下:
结论一:对于@Transactional可以保证RuntimeException错误的回滚,如果想保证非RuntimeException错误的回滚,需要加上rollbackFor = Exception.class 参数。 结论二:try catch只是对异常是否可以被@Transactional 感知 到有影响。如果错误抛到切面可以感知到的地步,那就可以起作用。 结论三: 由于REQUIRED属性,“两个事务”其实是一个事务,处理能力看报错时刻,是否添加了处理非RuntimeException的能力。
|