概述
业务中经常会遇到分布式事务失效的场景;通常情况下分析下两边的xid
是否一致,就可以初步判定原因;
我这边正好遇到openfeign
调用时其中一个rm抛异常,其他rm没回滚的现象;
排查了下发现tm和第一个rm
注册到seata
的xid
就不通;
然后看了下相关代码,发现openfeign
的拦截器中没有对xid
进行传递,后续传递xid
之后,分布式事务后面回滚就ok
了;
当前环境
jdk:1.8
seata-spring-boot-starter:1.6.1
spring-cloud-dependencies:2021.0.5
spring-cloud-alibaba-dependencies:2021.0.5.0
解决方案
在feign拦截器中传递seata的xid
package com.xxx.xxx.xxx.config;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
// 添加拦截器,所有内部服务调用都带上token
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
//feign seata xid传递
seataHeadProcess(requestTemplate);
}
};
}
/**
* 传递seata的全局xid
*/
private void seataHeadProcess(RequestTemplate requestTemplate){
// 从 seata 的 RootContext 中获取当前 XID
String xid = RootContext.getXID();
if (StrUtil.isBlank(xid)) return;
requestTemplate.header(RootContext.KEY_XID, xid);
}
}
源码分析
一般springboot
中的先找xxxAutoConfiguration
然后在SeataAutoConfiguration
的同级目录下发现了SeataHttpAutoConfiguration
,就是这个了;
然后一路点进去,最后发现在
io.seata.integration.http.TransactionPropagationInterceptor
中就看到了关于http
请求头中xid
的相关处理