开发者社区 > 云原生 > 中间件 > 正文

全局异常处理导致seata分布式事务无法回滚问题,有人用AOP的方法解决过吗,多个服务怎么弄?

全局异常处理导致seata分布式事务无法回滚问题,有人用AOP的方法解决过吗,多个服务怎么弄?

展开
收起
鸡蛋灌饼儿 2023-01-30 11:37:59 422 0
4 条回答
写回答
取消 提交回答
  • 使用AOP手动开启全局事务并进行回滚。

    @Aspect
    @Component
    @Slf4j
    public class WorkAspect {
    
        @Before("execution(* com.trs.slivlooncloud.service.*.*(..))")
        public void before(JoinPoint joinPoint) throws TransactionException {
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            Method method = signature.getMethod();
            GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
            tx.begin(300000, "tran");
            log.info("**********创建分布式事务完毕 {}" , tx.getXid());
        }
    
        @AfterThrowing(throwing = "e", pointcut = "execution(* com.trs.slivlooncloud.service.*.*(..))")
        public void doRecoveryActions(Throwable e) throws TransactionException {
            log.info("方法执行异常:{}", e.getMessage());
            if (!StringUtils.isBlank(RootContext.getXID())) {
                GlobalTransactionContext.reload(RootContext.getXID()).rollback();
            }
        }
    
    }
    

    ——参考来源于SEATA官方文档

    2023-12-23 20:03:19
    赞同 1 展开评论 打赏
  • 北京阿里云ACE会长

    全局异常处理导致 Seata 分布式事务无法回滚的问题,可以使用 AOP(面向切面编程)的方法进行解决。在 SpringBoot 项目中,可以通过创建一个切面类,使用 @Around 注解环绕通知方法,捕获全局异常,然后通过 Seata 的 API 进行事务回滚。
    以下是一个简单的示例:

    1. 首先,创建一个切面类,例如 GlobalExceptionHandlerAspect:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    @Aspect
    @Component
    public class GlobalExceptionHandlerAspect {
    @Pointcut("@annotation(com.example.globalexception.annotation.GlobalException)")
    public void pointcut() {
    }
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    try {
    return joinPoint.proceed();
    } catch (Exception e) {
    // 处理全局异常
    handleGlobalException(e);
    // 进行事务回滚
    return null;
    }
    }
    private void handleGlobalException(Exception e) {
    // 记录日志等操作
    // ...
    }
    }

    1. 创建一个全局异常注解 GlobalException:

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface GlobalException {
    }

    1. 在需要处理全局异常的方法上添加 @GlobalException 注解:

    @Service
    public class SomeService {
    @GlobalException
    public void someMethod() {
    // ...
    }
    }

    这样,在执行带有 @GlobalException 注解的方法时,如果发生全局异常,切面类中的 handleGlobalException 方法会被调用,然后通过 Seata 的 API 进行事务回滚。

    2023-12-19 20:36:16
    赞同 展开评论 打赏
  • AOP可以让你在不修改原有代码的情况下,对方法进行增强或者对全局异常进行统一处理。

    在Seata分布式事务中,如果某个服务出现异常,可以通过AOP来捕获这个异常,然后进行相应的处理,以保证分布式事务的正确性。

    下面是一个简单的示例,演示如何使用AOP来处理全局异常:
    1.定义一个注解,用于标记需要拦截的方法:

    @Retention(RetentionPolicy.RUNTIME)  
    @Target(ElementType.METHOD)  
    public @interface Transactional {  
    }
    

    2.创建一个AOP切面,实现MethodInterceptor接口:

    @Aspect  
    @Component  
    public class TransactionalAspect implements MethodInterceptor {  
        @Around("@annotation(Transactional)")  
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {  
            try {  
                return joinPoint.proceed(); // 执行方法  
            } catch (Exception e) {  
                // 处理异常,例如记录日志、回滚事务等  
                throw e; // 抛出异常,以触发Seata分布式事务回滚  
            }  
        }  
    }
    

    3.在需要使用@Transactional注解的方法上添加该注解:

    @Service  
    public class MyService {  
        @Transactional  
        public void myTransactionalMethod() {  
            // 执行分布式事务操作  
        }  
    }
    

    4.如果在myTransactionalMethod()方法中发生了异常,AOP切面会捕获到这个异常,并抛出给Seata分布式事务管理器,从而触发回滚事务。
    5.对于多个服务的情况,只需要在每个服务中重复上述步骤即可。确保每个服务中的方法都使用@Transactional注解,并配置相应的AOP切面。这样,无论哪个服务发生异常,Seata分布式事务都可以正确回滚。

    2023-12-14 16:57:31
    赞同 展开评论 打赏
  • 在微服务架构下,使用Seata进行分布式事务管理可能会遇到一些挑战。当全局异常处理导致Seata无法正确回滚事务时,这通常发生在使用了AOP全局异常处理的场景中。具体而言,如果一个事务(例如A事务)调用了另一个事务(例如B事务),并且B事务出现了异常,那么即使在A事务中设置了事务回滚,也可能导致事务回滚失败。

    这是因为当全局异常被内部处理(比如通过自定义的全局异常AOP拦截器)后,Seata不会再处理这个异常信息,从而导致事务回滚失败。

    解决方案有几个:

    1. 手动回滚:在捕获到异常后,在代码中手动进行事务回滚。

    2. 避免全局异常拦截:确保所有参与分布式事务的接口不被全局异常AOP拦截。这样,当异常发生时,Seata能够正确地处理它并执行相应的回滚操作。

    3. 配置Seata:确保Seata服务已经正确配置和启动。如果Seata服务和微服务不在同一个局域网内,需要指定IP和端口号来启动Seata服务。

    2023-12-13 16:51:59
    赞同 展开评论 打赏

为企业提供高效、稳定、易扩展的中间件产品。

相关电子书

更多
让 MySQL 原生分布式触手可及 立即下载
云原生时代下的分布式云多集群管理-容灾,弹性,多集群负载分布 立即下载
《Seata 1.3 新特性以及如何参与社区》 立即下载