springboot中使用AOP手动处理事务回滚

我有一个del的方法,当移除某个对象的时候,我需要相应的移除n个数据,这种情况下,除非其中某一个抛出了异常,事务才会回滚,但是我会在处理第n个数据的情况下,返回false,也需要让这个事务回滚,我该怎么处理呢

    @Override
    @Transactional
    public Result del(Long id) {
        AiKnowledgeBase knowledgeBase = getById(id);
        if (knowledgeBase == null) {
            return Result.error("数据异常");
        }
        if (removeById(id)) {
            //移除相关的config ,更新知识库的数量
            Result configResult = aiConfigService.delConfigByKlbId(id);
            if (configResult.isError()) {
                return configResult;
            }
            //移除相关的file
            Result fileResult = aiFileService.delFileByKlbId(id);
            if (fileResult.isError()) {
                return fileResult;
            }
            //移除相关的doc
            Result docResult = aiDocService.delDocByKlbId(id);
            if (docResult.isError()) {
                return docResult;
            }
            //移除vdb中的表
            Result result = vdbCollectionService.removeCollection(knowledgeBase.getVdbResourceId().toString(), "KDB_" + knowledgeBase.getId());
            if (result.isError()) {
                return result;
            } else {
                return Result.success();
            }
        } else {
            return Result.error("删除失败");
        }
    }
@Aspect
@Component
public class ResultErrorAspect {
    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object aroundTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            result = joinPoint.proceed();
            // 检查返回结果,判断是否需要回滚
            if (shouldRollback(result)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } catch (Exception e) {
            // 发生异常时也可以根据情况回滚
            if (shouldRollbackOnException(e)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            throw e;
        }
        return result;
    }

    private boolean shouldRollback(Object result) {
        // 根据业务逻辑判断是否需要回滚
        // 示例:假设 result 是一个自定义的 Result 对象,isError 表示是否出错
        return result instanceof Result && ((Result) result).isError();
    }

    private boolean shouldRollbackOnException(Exception e) {
        // 根据异常类型判断是否需要回滚
        return true; // 这里可以根据实际情况调整
    }
}

 springboot中使用AOP手动处理事务回滚_第1张图片

在代码示例中,del 方法上标注了 @Transactional 注解,这意味着整个方法会在一个事务中执行。如果该方法中的任何部分抛出了未捕获的异常或错误,并且该异常不是事务管理器被配置为忽略的异常类型(如 RuntimeExceptionError),则整个事务将会回滚。

通过AOP实现了一个环绕通知来手动控制事务的回滚行为,根据返回结果判断是否需要回滚。具体来说,在 aroundTransaction 方法中,检查了 Result 对象的 isError 方法的返回值。如果它返回 true,调用了 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 来标记当前事务为仅回滚状态。

在 del 方法中,如果你调用 aiDocService.delDocByKlbId(id) 返回的结果 docResult.isError()true,然后你直接返回了这个结果,此时你的AOP切面会捕捉到这个返回值并触发回滚,因为你在 shouldRollback 方法中定义了当 Result 对象的 isError 方法返回 true 时应该回滚。因此,在这种情况下,del 方法中的所有先前操作都会被回滚。

这种情况也会触发二次回滚么?

分析

如果 aiFileService.delFileByKlbId(id) 和 aiDocService.delDocByKlbId(id) 返回的 Result 对象的 isError() 方法都返回 true,这三个事务(del 方法的事务、delFileByKlbId 方法的事务和 delDocByKlbId 方法的事务)是否都会回滚。

1. 事务传播行为

在 Spring 中,@Transactional 注解有一个 propagation 属性,用于指定事务的传播行为,默认值是 Propagation.REQUIREDPropagation.REQUIRED 表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

在你的代码中,del 方法、delFileByKlbId 方法和 delDocByKlbId 方法都有 @Transactional 注解,假设它们都使用默认的传播行为 Propagation.REQUIRED,那么 delFileByKlbId 方法和 delDocByKlbId 方法会加入到 del 方法创建的事务中,它们实际上是同一个事务。

2. AOP 切面的作用

你定义的 ResultErrorAspect 切面会拦截所有带有 @Transactional 注解的方法。当 delFileByKlbId 方法和 delDocByKlbId 方法返回的 Result 对象的 isError() 方法返回 true 时,shouldRollback 方法会返回 true,从而调用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 方法将当前事务标记为回滚。

由于这三个方法使用的是同一个事务(基于默认的传播行为),一旦其中任何一个方法触发了回滚标记,整个事务都会回滚。

结论

如果 aiFileService.delFileByKlbId(id) 和 aiDocService.delDocByKlbId(id) 返回的 Result 对象的 isError() 方法都返回 true,并且这三个方法的 @Transactional 注解都使用默认的传播行为 Propagation.REQUIRED,那么这三个方法所在的事务会回滚。因为它们实际上是同一个事务,只要其中任何一个方法触发了回滚标记,整个事务都会回滚。

注意事项

  • 异常处理:在 ResultErrorAspect 切面中,shouldRollbackOnException 方法直接返回 true,这意味着所有异常都会触发回滚。你可以根据实际情况调整这个方法,只对特定的异常类型进行回滚。
  • 事务传播行为:如果 delFileByKlbId 方法和 delDocByKlbId 方法的 @Transactional 注解指定了不同的传播行为(如 Propagation.REQUIRES_NEW),那么它们会创建新的事务,与 del 方法的事务相互独立,回滚情况会有所不同。

你可能感兴趣的:(spring,boot,java,后端)