关于在微服务下跨库跨表的闲言碎语

原创
2021/07/28 19:47
阅读数 789

目前微服务盛行的当下,微服务的划分就带来数据库的分而治之,我们再也不能像之前那样一条sql 要啥拿啥数据了,这是我们所有实施微服务架构都要面临的问题,一般我们的解决方案无非两种。

第一,将各个业务集中采集到中心数据库,在中心数据库拿到关联的数据

第二,建立视图,也就是命令集合,提前讲我们需要的聚合数据准备好,需要的时候获取就好了。

我们对比这两个解决方案的优缺点:

第一种方案貌似是比较理想,延迟又低,这样导致我们已经分开的数据库,有整合到了一起,而且很难控制从数据中心获取数据的查询颗粒度,如控制不好,sql 逻辑混乱复杂,服务也就白拆了,ok,那我隔离研发人员对数据中心的操作权限,提供需求接口由专人负责,貌似可以降低这个问题的严重性,但还是存在,数据中心是肯定要有的,无论是后续大数据分析,还是聚合查询都有其不可或缺的必要性,但是也要和我们平时需要的实时查询的数据场景分开,数据中心更多的是在冷库归档和数据分析上的场景多一些。

第二种方法,建立视图,也就是诸多个命令集合,提前将数据准备好,随用随拿,看似还不错,就类似数据库的视图,方便,快捷,但会存在数据不一致问题,很多时候我们微服务之间聚合数据是有实效的要求的,ok,那我搭配 event bus 事件总线做数据同步,理论上也是可以达到目的的,既然涉及到数据同步就避免不了最终一致性问题,特别是跨服务之间,就算优化到四九原则,某个特殊场景还是依靠人肉来解决,所以成本高低就要靠自己来评估了。

综合来看,第二种方式稍微好一些,但是要评估自己的成本是不适合这样做,但无论是哪种方案也比不采取任何措施采用硬编码的方式进行跨库跨表的数据聚合,你会发现一个人一个风格,一个人维护着一堆不堪入眼的代码,假如这个公司新人旧人流转率再高一点,估计代码写不了多久就要重新开始了。

polymeric 是一个在微服务下跨库跨表的数据聚合实现,使用声明式配置将需要跨库跨表的字段,自动匹配远程数据源,规避良莠不一的聚合方式,降低代码量。

polymeric 结合 mybatis 查询结果的前置下,实现远程数据查询并反写到 mybatis 的查询结果中, 提供自由实现分页没有任何侵入,实现了轻松跨库,跨表,代码干净清爽并存的解决方案。

使用说明

  1.  引入 polymeric-spring-boot-starter
    <dependency>    
            <groupId>com.cdg.polymeric</groupId>    
            <artifactId>polymeric-spring-boot-starter</artifactId>    
            <version>2.0.0-SNAPSHOT</version>    
    </dependency>    
  1.  在spring boot 工程中 根据自己实际需要增加缓存配置
    ploymeric:    
      enabled: true #默认开启    
      guavaCacheNumMaxSize: 1000 #guava缓存的键值数    
      guavaCacheRefreshWriteTime: 10 #guava更新缓存的下一次时间,分钟    
      guavaCacheRefreshThreadPoolSize: 10 #guava刷新线程池线程数量    

       
3.  在需要跨库跨表的字段或者vo上增加声明式注解配置,比如案例如下

第一种使用方式:  

       
    聚合服务方: 

    @Polymeric(key = "id",args = Long.class,feign = BasicDataFeignClientService.class,method = "getCustomerNameById")    
    public class CustomerVo {

      private Long id;

      @PolymericValue(name = "customerName",enableCache = true)    
      private String customerName;

      private String address;

    
      private String phone;    
}    

    远程数据源:

    @GetMapping(value = "/getCustomerNameById")    
    @ApiOperation(value = "测试聚合组件")    
    public Map getCustomerNameById(@RequestParam(name = "id") Long id) {    
        Map result = new HashMap();    
        result.put("customerName","wyp");    
        return result;    
    }    
@Polymeric    
key: 远程数据源需要查询的参数    
args: 远程数据源的参数类型    
feign:支持openfeign 的feign客户端    
method: feign客户端下调用的方法名    
@PolymericValue    
name:远程数据源需要聚合的字段名称    
enableCache: 是否开启缓存    

注:这里是调用一次远程数据源反写多个字段,比较适合一个vo中多个字段需要跨库跨表查询的场景,当所有字段都开启了缓存,才会走一级缓存,否则至多查询一次远程数据源。

第二种使用方式:

    聚合服务方:  
      

public class CustomerVo {    
            
        private Long id;    
            
        @PolymericFiled(key = "id",args = Long.class,feign = BasicDataFeignClientService.class,method = "getCustomerNameById",enableCache = true)    
        private String customerName;    
            
        private String address;    
            
            
        private String phone;    
            
            
      }

也可以将查询配置在字段上,此场景比较适合vo至多有一个需要查询的字段,否在推荐使用 @Polymeric

@PolymericFiled    
key: 远程数据源需要查询的参数    
args: 远程数据源的参数类型    
feign:支持openfeign 的feign客户端    
method: feign客户端下调用的方法名    

加qq群学习交流

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部