全局异常处理导致seata分布式事务无法回滚问题,有人用AOP的方法解决过吗,多个服务怎么弄?
使用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官方文档。
全局异常处理导致 Seata 分布式事务无法回滚的问题,可以使用 AOP(面向切面编程)的方法进行解决。在 SpringBoot 项目中,可以通过创建一个切面类,使用 @Around 注解环绕通知方法,捕获全局异常,然后通过 Seata 的 API 进行事务回滚。
以下是一个简单的示例:
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) {
// 记录日志等操作
// ...
}
}
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 {
}
@Service
public class SomeService {
@GlobalException
public void someMethod() {
// ...
}
}
这样,在执行带有 @GlobalException 注解的方法时,如果发生全局异常,切面类中的 handleGlobalException 方法会被调用,然后通过 Seata 的 API 进行事务回滚。
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分布式事务都可以正确回滚。
在微服务架构下,使用Seata进行分布式事务管理可能会遇到一些挑战。当全局异常处理导致Seata无法正确回滚事务时,这通常发生在使用了AOP全局异常处理的场景中。具体而言,如果一个事务(例如A事务)调用了另一个事务(例如B事务),并且B事务出现了异常,那么即使在A事务中设置了事务回滚,也可能导致事务回滚失败。
这是因为当全局异常被内部处理(比如通过自定义的全局异常AOP拦截器)后,Seata不会再处理这个异常信息,从而导致事务回滚失败。
解决方案有几个:
手动回滚:在捕获到异常后,在代码中手动进行事务回滚。
避免全局异常拦截:确保所有参与分布式事务的接口不被全局异常AOP拦截。这样,当异常发生时,Seata能够正确地处理它并执行相应的回滚操作。
配置Seata:确保Seata服务已经正确配置和启动。如果Seata服务和微服务不在同一个局域网内,需要指定IP和端口号来启动Seata服务。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。