暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

自定义水平分库分表策略【hint分片】

1435

背景

    在之前的公众号文章中,不管是自定义范围分片策略还是精准分片策略,其分片键的值都是直接从sql语句中解析出来。如果有这样一个sql需要:select * from product_order where out_trade_no='fdjaslkji394298';只需要路由到ds1数据库的product_order_0表中,不需要广播到所有的表。那么这个需求无法通过之前的方式实现,因为这条sql语句中没有用到分片键。这时候就需要使用到hint分片策略。


hint分片策略介绍

    hint的中文意思:提示、暗示;

    这种分片策略无需配置文件进行配置分片健,分片健值也不再从 SQL中解析【外部手动在业务逻辑代码中指定分片健值】做为分库分表依据, 让 SQL在指定的分库、分表中执行;

    通过Hint代码指定的方式而非SQL解析的方式分片的策略;

    Hint策略会绕过SQL解析的,对于这些比较复杂的需要分片的查询,Hint分片策略性能可能会更好;

    可以让不涉及分片键的sql去指定的某个库某个表进行执行。


1、编写Hint分库的策略类,实现HintShardingAlgorithm<T>  T代表需要用到的分片值的类型

    public class CustomDBHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    /**
    *
    * @param dataSourceNames 数据源集合
    * 在分库时值为所有分片库的集合 databaseNames
    * 分表时为对应分片库中所有分片表的集合 tablesNames
    *
    * @param hintShardingValue 分片属性,包括
    * logicTableName 为逻辑表,
    * columnName 分片健(字段),hint策略此处为空 ""
    *
    * value 【之前】都是 从 SQL 中解析出的分片健的值,用于取模判断
    * HintShardingAlgorithm不再从SQL 解析中获取值,而是直接通过
    * hintManager.addTableShardingValue("product_order", 1)参数进行指定
    * @return
    */


    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, HintShardingValue<Long> hintShardingValue) {
    Collection<String> result = new ArrayList<>();
    for(String datasourceName: dataSourceNames){


    for(Long shardingValue : hintShardingValue.getValues()){
    //通过传入的指定分片value%数据源length 得到应该命中哪个库
    String value = shardingValue % dataSourceNames.size()+"";
    if(datasourceName.endsWith(value)){
    result.add(datasourceName);
    }
    }
    }
    return result;
    }
    }
    复制

    2、编写编写Hint分表的策略类,实现HintShardingAlgorithm<T>  T代表需要用到的分片值的类型

      public class CustomTableHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
      /**
      *
      * @param dataSourceNames 数据源集合
      * 在分库时值为所有分片库的集合 databaseNames
      * 分表时为对应分片库中所有分片表的集合 tablesNames
      *
      * @param hintShardingValue 分片属性,包括
      * logicTableName 为逻辑表,
      * columnName 分片健(字段),hint策略此处为空 ""
      *
      * value 【之前】都是 从 SQL 中解析出的分片健的值,用于取模判断
      * HintShardingAlgorithm不再从SQL 解析中获取值,而是直接通过
      * hintManager.addTableShardingValue("product_order", 1)参数进行指定
      * @return
      */


      @Override
      public Collection<String> doSharding(Collection<String> dataSourceNames, HintShardingValue<Long> hintShardingValue) {


      Collection<String> result = new ArrayList<>();
      for(String datasourceName: dataSourceNames){
      for(Long shardingValue : hintShardingValue.getValues()){
      //通过传入的指定分片value%数据源length 得到应该命中哪个表
      String value = shardingValue % dataSourceNames.size()+"";
      if(datasourceName.endsWith(value)){
      result.add(datasourceName);
      }
      }
      }
      return result;
      }
      }
      复制


      3、编写application.properties

        spring.application.name=xdclass-sharding-jdbc
        server.port=8080


        # 打印执行的数据库以及语句
        spring.shardingsphere.props.sql.show=true


        # 数据源 db0
        spring.shardingsphere.datasource.names=ds0,ds1


        # 第一个数据库
        spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
        spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
        spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/xdclass_shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        spring.shardingsphere.datasource.ds0.username=root
        spring.shardingsphere.datasource.ds0.password=liangmerlin1025


        # 第二个数据库
        spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
        spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
        spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/xdclass_shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        spring.shardingsphere.datasource.ds1.username=root
        spring.shardingsphere.datasource.ds1.password=liangmerlin1025


        #配置workId
        spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1


        #id生成策略
        spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
        spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE


        #精准分片-水平分表
        # 指定真实节点,配置数据节点,在 Spring 环境中建议使用 $->{...}
        spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}


        #hint分库策略
        spring.shardingsphere.sharding.tables.product_order.database-strategy.hint.algorithm-class-name=net.xdclass.strategy.CustomDBHintShardingAlgorithm
        #hint分表策略
        spring.shardingsphere.sharding.tables.product_order.table-strategy.hint.algorithm-class-name=net.xdclass.strategy.CustomTableHintShardingAlgorithm
        复制


        4、业务代码编写如下:

        这里是和前两种从sql解析分片键值的分片策略最大的不同,即需要手动指定当前这条sql的分片键值。然后在执行sql的时候就只会路由指定的表

          /**
          * 正常可以用AOP进行实现清除历史规则,真实业务中分片分表的键值可以由外界传入
          */
          @Test
          public void testHit(){
          //清除历史规则
          HintManager.clear();
          //获取对应的实例
          HintManager hintManager = HintManager.getInstance();
          //设置库的分片键值,value=3是用于库分片取模,通过分片逻辑命中ds1库
          hintManager.addDatabaseShardingValue("product_order",3L);
          //设置表的分片键值,value=8是用于表分片取模,通过分片逻辑命中product_order_0表
          hintManager.addTableShardingValue("product_order",8L);


          //如果在读写分离数据库中,Hint 可以强制读主库(主从复制存在一定延时,但在业务场景中,可能更需要保证数据的实时性)
          //hintManager.setMasterRouteOnly();


          //对应sql语句的id值不做为分片键的值,仅仅只有查询功能
          productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id",66L));


          }
          复制


          通过运行发现,这条sql确实只是命中了ds1库的product_order_0表


          关于leetcode算法训练营:

              加我微信号私聊参加训练营,尤其是想进入大厂工作的同学,算法是绕不过去的坎,我自己花了三年时间刷算法,总结思路,刷各种数据结构课程,加入我的训练营,我手把手以在线直播课的形式带你理思路,手把手带你写代码,让你真正体会算法之美~,同时遇到不明白的地方可以直接课上和我沟通,彻底解决你的代码困难症~

          本人用c++刷了800道左右的算法,java语言刷了600道左右的算法题,并对这些题做了详细的个人总结。本科期间系统学习了数据结构与算法课程,同时考研过程中写完了率辉主编的《2020年数据结构高分笔记》和《数据结构1000题》,看完的视频包括《mooc浙大数据结构国家精品课程》和《王道考研408数据结构课程》,《王道2019年算法题讲解视频》,最终以初试专业第三名进入了北理工软件工程专业。熟悉并掌握常见的数据结构,比如链表、数组、树、图、队列、堆栈等等,精通数据结构教材中的所有算法,比如常见的遍历算法、动态规划,递归,回溯,剪枝,并查集,最短路径,拓扑排序等,所以快加入训练营吧,我们一起进步

          奔跑的小梁,公众号:梁霖编程工具库我决定了,算法文档开源!!


          文章转载自梁霖编程工具库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论