关于Spring嵌套事务异常问题
异常截图
异常信息: Transaction silently rolled back because it has been marked as rollback-only
代码展示
UserServiceImpl
@Transactional(rollbackFor = Exception.class)
public void test(){
friendService.saveFriend(10000000000L, Arrays.asList(10000000000L));
try {
friendService.test();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("123");
}
FriendServiceImpl
@Transactional
public void test() {
System.out.println(1/0);
friendRepo.deleteByUid(10000000000L);
}
UserTest
@Autowired
private UserService userService;
@Test
public void test(){
userService.test();
}
产生原理
两个方法都加了事务注解,并且两个方法都会受到到事务管理的拦截器增强,并且事务传播的方式都是默认的,也就是REQUIRED,当已经存在事务的时候就加入事务,没有就创建事务。这里A和B都受事务控制,并且是处于同一个事务的。
A调用B,A中抓了B的异常,当B发生异常的时候,B的操作应该回滚,但是A吃了异常,A方法中没有产生异常,所以A的操作又应该提交,二者是相互矛盾的。
spring的事务关联拦截器在抓到B的异常后就会标记rollback-only为true,当A执行完准备提交后,发现rollback-only为true,也会回滚,并抛出异常告诉调用者。
抑制异常方式
1.在catch中添加TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
2.尽量不要再service中try-cache
扩展
spring的事务处理方式才用的是AOP模式,走的是代理。当内部方法嵌套调用则并不会走代理就不会产生事务嵌套异常。需要走代理则采用注入类方式调用。