问题
最近上线了一个新功能,在某个特定场景下保存数据时,一直提示Transaction rolled back because it has been marked as rollback-only
异常。
结论
先说结论,**是因为@Transactional 注解使用的有问题。**我们这个case下将其中一个类上的@Transactional注解去掉就好了。
问题是解决了,但是原因呢?得扒一扒。
原因
首先,再回顾下事务传播机制:https://blog.csdn.net/qq_17085835/article/details/84837253,(PS:如果你真的深刻理解了事务传播机制,就不用接着往下看了)
场景
我们的场景下是,类A的事务方法调用了类B的事务方法,两个类上均设置了@Transactional注解,注解属性均为默认。
问题现象是:B中的方法会抛出异常,当在A中catch了B的异常后,A仍然出现异常并回滚。
具体代码简化
@Transactional
class A {
private B b;
public C funca(){
try{
b.funcb();
}catch(Exception e){
return someThing;
}
}
}
@Transactional
class B {
private B b;
public D funcb(){
//。。。
throw new Exception()
}
}
默认情况下,事务传播机制是PROPAGATION_REQUIRED
,也就是说有事务就用当前的事务,没有就新开一个事务。
对于上面的case来说,调用A开启了一个事务,调用B时,沿用了A的事务;那么B抛出异常,会将事务标记为异常回滚,即使在A的方法里捕捉到了B方法的异常也没有用,A的事务切面执行到时,由于已经被标记为回滚了所以一定会回滚。
问题在与A、B使用的事务传播机制,还有事务注解的使用范围。这个case中,由于B类上的事务注解,评估后发现实际上没有用,所以去掉就好了。
实践出真知!