项目场景:
微服务场景下,配置了统一全局异常处理,导致seata在AT模式下无法正常回滚问题
问题描述:
假设服务A调用服务B, 服务B发生异常,由于全局异常处理的存在(@ControllerAdvice), seata 无法拦截到B服务的异常,从而导致分布式事务未生效
解决方案:
-
程序代码各自判断RPC响应码是否正常,再抛出异常
-
RPC接口不配置全局异常
-
利用AOP切面解决
代码实现:
本篇文章使用AOP切面解决
/**
* 全局事务处理切面
* @author enbei
* @Date 2022/12/8
*/
@Aspect
@Component
@Slf4j
public class GlobalTransactionAop {
@Pointcut("within(com.ddwl..*.controller..*)")
public void controllerAspect() {}
// @Before("serviceAspect() && !@within(javax.websocket.server.ServerEndpoint)")
@Before("controllerAspect()")
public void before(JoinPoint joinPoint) throws TransactionException {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
// GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
if (StrUtil.isNotEmpty(RootContext.getXID())){
log.info("拦截到需要分布式事务的方法:{},分布式全局事务XID:{}", method.getName(),RootContext.getXID());
}
}
/**
* 用于解决全局异常处理导致的全局事务失效问题
*/
//@AfterThrowing(throwing = "e", pointcut = "serviceAspect() && !@within(javax.websocket.server.ServerEndpoint)")
@AfterThrowing(throwing = "e", pointcut = "controllerAspect()")
public void doRecoveryActions(Throwable e) throws TransactionException {
if (StrUtil.isNotEmpty(RootContext.getXID())) {
log.info("分布式全局事务XID:{}", RootContext.getXID());
GlobalTransactionContext.reload(RootContext.getXID()).rollback();
}
}
}