当前场景:app接口服务调用A服务和B服务。app接口内会回滚,A服务和B服务不会回滚。
@GlobalTransactional(rollbackFor = Exception.class)
public Result uploadFile(SaveLogDataReq req) {
System.out.println("seata全局事务id====================>"+ RootContext.getXID());
servieFeignA.addAAA(req);
servieFeignB.addBBB(req);
int i = 1/0;
return Resu.ok();
}
A服务:
public Result addAAA(SaveLogDataReq req) {
System.out.println("seata全局事务id====================>"+ RootContext.getXID());
//todo AAA代码逻辑......
return Resu.ok();
}
B服务:
public Result addBBB(SaveLogDataReq req) {
System.out.println("seata全局事务id====================>"+ RootContext.getXID());
//todo BBB代码逻辑......
return Resu.ok();
}
分析:查看打印日志显示,A服务和B服务的xid为空,或者与APP接口服务的xid不一致。
解决方案:
方案一:配置请求拦截器
public class MultipartSupportConfig implements RequestInterceptor {
/**
* 解决服务直接调用请求头不传递的问题
* @param template
*/
@Override
public void apply(RequestTemplate template) {
// 解决seata的xid未传递
String xid = RootContext.getXID();
template.header(RootContext.KEY_XID, xid);
}
}
//在feign中配置请求拦截器
@FeignClient(contextId="LogDataService",value = "LogDataService",configuration = MultipartSupportConfig.class)
public interface ServieFeignA {
@PostMapping(value = "/api/logdata/v1/log/save",consumes = MediaType.APPLICATION_JSON_VALUE)
public Result<String> save(@RequestBody SaveLogDataReq req);
}
方案二:使用spring-cloud-starter-alibaba-seata自动配置(推荐)
之前使用的是seata-spring-boot-starter配置,这里的seata自动配置不会对feign进行处理,所以fein调用不会传xid,导致全局事务未生效
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
所以去掉这个maven配置,使用spring-cloud-starter-alibaba-seata替代。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
注意:
1,异常需要层层往上抛,如果你在子服务将异常处理的话(比如全局异常处理GlobalExceptionHandler),seata会认为你已经手动处理了异常。
2,出现事务失效的情况下,优先检查 RootContext.getXID() ,xid是否传递且一致。
3,主服务加上@GlobalTransactional注解即可,被调用服务不用加@GlobalTransactional和@Transactional.
4,@GlobalTransactional(rollbackFor = Exception.class)最好加上rollbackFor = Exception.class,表示遇到Exception都回滚,不然遇到有些异常(如自定义异常)则不会回滚。