详解Spring Boot微服务如何集成fescar解决分布式事务问题

作者:Scott Lewis 时间:2022-01-21 18:43:51 

什么是fescar?

关于fescar的详细介绍,请参阅fescar wiki。

详解Spring Boot微服务如何集成fescar解决分布式事务问题

传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交成功后一起提交,或有一个局部事务预提交失败后一起回滚,最后释放全局锁。锁持有的时间较长,会对并发造成较大的影响,死锁的风险也较高。

详解Spring Boot微服务如何集成fescar解决分布式事务问题

fescar的创新之处在于,每个局部事务执行完立即提交,释放本地锁;它会去解析你代码中的sql,从数据库中获得事务提交前的事务资源即数据,存放到undo_log中,全局事务协调器在回滚的时候直接使用undo_log中的数据覆盖你提交的数据。

Spring Boot如何集成fescar?

我们可以从官方代码库中看到,fescar目前提供的示例是针对使用dubbo的服务,那Spring Boot的项目如何集成fescar呢?

详解Spring Boot微服务如何集成fescar解决分布式事务问题

和很多2PC提交协议(如tx_lcn)的解决方案一样,fescar也是在数据源处做了代理,和事务协调器进行通信,来决定本地事务是否回滚。所以,第一步,在你的spring boot项目中,首先应使用fescar提供的代理数据源作为你的数据源,例如:


DruidDataSource dataSource = initDataSource(dataSourceProps.get("url").toString(), dataSourceProps.get("username").toString(), dataSourceProps.get("password").toString());

DataSourceProxy proxy = new DataSourceProxy(dataSource);

然后,你需要创建一个Feign * ,把RootContext中的XID(XID用于标识一个局部事务属于哪个全局事务,需要在调用链路的上下文中传递)传递到上层调用链路。


@Component

public class RequestHeaderInterceptor implements RequestInterceptor {

@Override

public void apply(RequestTemplate template) {

String xid = RootContext.getXID();

if(StringUtils.isNotBlank(xid)){

template.header("Fescar-Xid",xid);

}

}

}

最后,你需要创建一个Http Rest请求 * ,用于把当前上下文中获取到的XID放到RootContext。


import com.alibaba.fescar.core.context.RootContext;

import org.apache.commons.lang.StringUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

public class FescarXidFilter extends OncePerRequestFilter {

protected Logger logger = LoggerFactory.getLogger(FescarXidFilter.class);

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

String xid = RootContext.getXID();

String restXid = request.getHeader("Fescar-Xid");

boolean bind = false;

if(StringUtils.isBlank(xid)&&StringUtils.isNotBlank(restXid)){

RootContext.bind(restXid);

bind = true;

if (logger.isDebugEnabled()) {

logger.debug("bind[" + restXid + "] to RootContext");

}

}

try{

filterChain.doFilter(request, response);

} finally {

if (bind) {

String unbindXid = RootContext.unbind();

if (logger.isDebugEnabled()) {

logger.debug("unbind[" + unbindXid + "] from RootContext");

}

if (!restXid.equalsIgnoreCase(unbindXid)) {

logger.warn("xid in change during http rest from " + restXid + " to " + unbindXid);

if (unbindXid != null) {

RootContext.bind(unbindXid);

logger.warn("bind [" + unbindXid + "] back to RootContext");

}
       }
     }
   }
 }
}

这样就完成了fescar的集成。

开始使用吧!

首先在项目中初始化两个Bean:


@Bean

public FescarXidFilter fescarXidFilter(){

return new FescarXidFilter();

}

@Bean

public GlobalTransactionScanner scanner(){

GlobalTransactionScanner scanner = new GlobalTransactionScanner("fescar-test","my_test_tx_group");

return scanner;

}

然后写两个服务,服务A调用服务B,并在A服务的调用方法上打上@GlobalTransactional标签:


@GlobalTransactional(timeoutMills = 300000, name = "fescar-test-tx")

public void testFescar() throws BusinessException {

DictionVO dictionVO = new DictionVO();

dictionVO.setCode("simidatest");

dictionVO.setValue("1");

dictionVO.setDesc("simidatest");

dictionVO.setAppId("sso");

commonService.createDiction(dictionVO);//远程调用服务B

areaMapper.deleteAreaBySysNo(2);//本地事务

throw new BusinessException("主动报错");

}

最后,两个项目中添加application.conf文件,用于告诉客户端如何与分布式协调器通信,官方示例中有这个文件,就不在此贴代码啦,application.conf传送门

启动事务协调器,sh fescar-server.sh 8091 ~/dksl/git/fescar/data,启动你的项目,开始测试吧!

last thing

分布式事务作为微服务应用中的老大难问题,在现有的解决方案中,个人认为fescar是目前最轻量并且代价最小的一种解决方案。目前的版本,事务协调器还不能分布式部署,官方给出的路线图是在三月底会有第一个生产可用版本。让我们一起参与到fescar的社区中,共同推动fescar生态建设,让落地微服务不必再担心分布式事务的问题。

来源:http://www.cnblogs.com/DKSL/p/fescar.html

标签:Spring,Boot,fescar,分布式事务
0
投稿

猜你喜欢

  • Android四大组件之广播BroadcastReceiver详解

    2023-03-29 23:41:14
  • DevExpress实现GridControl根据列选中一行

    2021-08-16 05:23:19
  • android自定义view之模拟qq消息拖拽删除效果

    2023-01-29 11:48:34
  • Mybatis 动态SQL的几种实现方法

    2023-11-10 12:15:15
  • Java利用栈实现简易计算器功能

    2022-05-08 16:57:25
  • c++函数指针使用示例分享

    2022-01-20 17:48:26
  • Android中EditText和AutoCompleteTextView设置文字选中颜色方法

    2022-12-05 04:45:30
  • 详解C#开发Android应用程序的流程

    2021-08-11 21:32:59
  • android Retrofit2网络请求封装介绍

    2022-02-09 18:46:49
  • springboot自定义过滤器的方法

    2021-07-29 05:36:53
  • c#创建圆形类Circle、矩形类实现代码

    2023-08-18 19:59:12
  • C#操作ftp类完整实例

    2021-09-02 22:45:30
  • Java实战之在线寄查快递系统的实现

    2023-08-10 21:52:23
  • Java多线程之Future设计模式

    2022-07-19 05:28:25
  • Spring boot的上传图片功能实例详解

    2022-10-09 09:52:00
  • java面向对象之人机猜拳小游戏

    2021-12-20 18:12:34
  • idea中Maven镜像源详细配置步骤记录(对所有项目)

    2022-12-17 14:27:56
  • kill命令在Java应用中使用的注意事项小结

    2023-11-11 13:01:55
  • java使用字符画一个海绵宝宝

    2023-09-08 09:45:19
  • android tv列表焦点记忆实现的方法

    2023-08-25 19:36:53
  • asp之家 软件编程 m.aspxhome.com