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

 更新时间:2019年01月30日 11:04:57   作者:Scott Lewis  
这篇文章主要介绍了详解Spring Boot微服务如何集成fescar解决分布式事务问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

什么是fescar?

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

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

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

Spring Boot如何集成fescar?

我们可以从官方代码库中看到,fescar目前提供的示例是针对使用dubbo的服务,那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生态建设,让落地微服务不必再担心分布式事务的问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringSecurity 自定义表单登录的实现

    SpringSecurity 自定义表单登录的实现

    这篇文章主要介绍了SpringSecurity 自定义表单登录的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Java中MapStruct使用方法解析

    Java中MapStruct使用方法解析

    这篇文章主要介绍了Java中MapStruct使用方法解析,接受请求参数都会使用一个vo类,这个vo类里封装了所有需要接受的参数,然后对参数进行业务逻辑处理,处理完后会持久化处理, 使用MapStruct可以快速帮你解决转换工作,需要的朋友可以参考下
    2023-10-10
  • jvm双亲委派 vs 破坏双亲委派理解加载器的权责分配

    jvm双亲委派 vs 破坏双亲委派理解加载器的权责分配

    这篇文章主要为大家介绍了jvm双亲委派 vs 破坏双亲委派对比来理解加载器的权责分配,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Springmvc国际化自动配置代码实现

    Springmvc国际化自动配置代码实现

    这篇文章主要介绍了Springmvc国际化自动配置代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java中数组越界异常的优雅解决方式

    Java中数组越界异常的优雅解决方式

    ‌数组越界报错通常发生在尝试访问数组中不存在的索引时,这可能导致程序崩溃或异常,这篇文章主要给大家介绍了关于Java中数组越界异常的优雅解决方式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • Java中线程死亡的几种情况实例分析

    Java中线程死亡的几种情况实例分析

    线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。下面这篇文章主要给大家介绍了Java线程死亡的几种情况,需要的朋友可以参考下。
    2017-01-01
  • 老生常谈java中cookie的使用

    老生常谈java中cookie的使用

    下面小编就为大家带来一篇老生常谈java中cookie的使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • WebSocket无法注入属性的问题及解决方案

    WebSocket无法注入属性的问题及解决方案

    这篇文章主要介绍了WebSocket无法注入属性的问题及解决方法,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • 浅谈用SpringBoot实现策略模式

    浅谈用SpringBoot实现策略模式

    本文主要介绍了SpringBoot实现策略模式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • 如何解决Maven打包时每次都出现Download maven-metadata.xml卡住问题

    如何解决Maven打包时每次都出现Download maven-metadata.xml卡住问题

    这篇文章主要介绍了如何解决Maven打包时每次都出现Download maven-metadata.xml卡住问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05

最新评论