两个事务方法导致异常抛出Transaction rolled back because it has been marked as rollback-only

异常现场(背景)

在springboot事物操作开发中,如果A方法调用B方法,A和B方法都在不同的类中,且A和B都加了@Transactional注解,A调用B方法时,将B方法try catch了。
代码:

@Service  
public class BService {  
      
    @Transactional(rollbackFor = Exception.class) 
    public void bMethod() {  
        // ... 业务逻辑 ...    
        throw new RuntimeException("B方法异常");  
    }  
}  

@Service  
public class AService {  
      
    @Autowired  
    private BService bService;  

    @Transactional(rollbackFor = Exception.class)  
    public void aMethod() {  
        try {  
            bService.bMethod();  
        } catch (Exception e) {  
            // 处理B方法的异常 
            // 可以记录日志或采取其他措施  
        }  
        // A方法的其他逻辑,继续执行  
    }  
}

问题产生原因

在Spring框架中,当使用@Transactional注解时,事务的边界通常是由Spring的AOP代理来控制的。如果在事务中发生异常并且没有被捕获,Spring会标记当前事务为“只回滚”(rollback-only),并在事务的边界处(通常是方法的退出点)执行回滚。
当A方法调用B方法,并且B方法因为异常而回滚了,但由于A方法捕获了异常并没有重新抛出,所以A方法的事务不会自动回滚,但由于B方法的事务已经被标记为“只回滚”,当A方法的事务试图提交时,它会发现它处于“只回滚”状态,并抛出一个异常,提示:Transaction rolled back because it has been marked as rollback-only

解决方式

现在的需求是,想要A继续执行不抛出异常,如果A异常,A的方法也会回滚,B异常也正常回滚,但B是单独的事务。很简单,如果B方法是一个可以独立处理其事务逻辑的服务,并且不需要A方法的事务上下文,可以让B方法独立地处理其事务。这样,B方法的异常就不会影响A方法的事务。
代码:

@Service  
public class BService {  
      
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void bMethod() {  
        // ... 业务逻辑 ...  
        // 如果这里抛出异常,只有B的事务会回滚  
        throw new RuntimeException("B方法异常");  
    }  
}  

@Service  
public class AService {  
      
    @Autowired  
    private BService bService;  

    @Transactional(rollbackFor = Exception.class)  
    public void aMethod() {  
        try {  
            bService.bMethod();  
        } catch (Exception e) {  
            // 处理B方法的异常,但A方法的事务不会受到影响  
            // 可以记录日志或采取其他措施  
        }  
        // A方法的其他逻辑,继续执行  
    }  
}
posted @ 2024-05-07 10:51  惊叫唤  阅读(13)  评论(0编辑  收藏  举报