• ShardingJdbc实战-分库分表



    基本配置

    逻辑表

    逻辑表是指:水平拆分的数据库或者数据表的相同路基和数据结构表的总称。比如用户数据根据用户id%2拆分为2个表,分别是:ksd_user0和ksd_user1。他们的逻辑表名是:ksd_user。
    在shardingjdbc中的定义方式如下:

    spring:
      shardingsphere:
        sharding:
          tables:
            # ksd_user 逻辑表名
            ksd_user:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分库分表数据节点 - actual-data-nodes

     tables:
            # ksd_user 逻辑表名
            ksd_user:
              # 数据节点:多数据源$->{0..N}.逻辑表名$->{0..N} 相同表
              actual-data-nodes: ds$->{0..2}.ksd_user$->{0..2}
               # 也可以这么写,不同数据源不同表
              actual-data-nodes: ds0.ksd_user$->{0..2},ds1.ksd_user$->{2..4}
              # 指定单数据源的配置方式-同一个数据源,不同表
              actual-data-nodes: ds0.ksd_user$->{0..4}
              # 全部手动指定
              actual-data-nodes: ds0.ksd_user0,ds1.ksd_user0,ds0.ksd_user1,ds1.ksd_user1,
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    寻找规则如下
    在这里插入图片描述

    分库分表的分片策略

    在这里插入图片描述
    分片策略由分片键和分片算法组成

    一、inline 行表达时分片策略

    对应InlineShardingStragey。使用Groovy的表达时,提供对SQL语句种的=和in的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开放,如:ksd_user${分片键(数据表字段)userid % 5} 表示ksd_user表根据某字段(userid)模 5.从而分为5张表,表名称为:ksd_user0到ksd_user4 。数据库也是如此。

        # 配置默认数据源ds1
        sharding:
          # 默认数据源,主要用于写,注意一定要配置读写分离 ,注意:如果不配置,那么就会把三个节点都当做从slave节点,新增,修改和删除会出错。
          default-data-source-name: ds0
          # 配置分表的规则
          tables:
            # ksd_user 逻辑表名
            ksd_user:
              key-generator:
                # 主键的列明,雪花算法,也可以是UUID
                column: id
                type: SNOWFLAKE
              # 数据节点:数据源$->{0..N}.逻辑表名$->{0..N}
              actual-data-nodes: ds$->{0..2}.ksd_user$->{0..2}
              # 拆分库策略,也就是什么样子的数据放入放到哪个数据库中。
              database-strategy:
                inline:
                  sharding-column: sex    # 分片字段(分片键)
                  algorithm-expression: ds$->{sex % 3} # 分片算法表达式
              # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
              table-strategy:
                inline:
                  sharding-column: age    # 分片字段(分片键)
                  algorithm-expression: ksd_user$->{age % 3} # 分片算法表达式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    grove表达式说明:

    • ${begin…end} 表示区间范围
    • ${[unit1,unit2,….,unitn]} 表示枚举值
    • 行表达式种如果出现连续多个 e x p r e s s s i o n 或 {expresssion}或 expresssion->{expression}表达式,整个表达时最终的结果将会根据每个子表达式的结果进行笛卡尔组合

    algorithm-expression行表达式

    在这里插入图片描述

    完整案例和配置如下

    • 准备三台服务器(测试用也可以用docker 安装三个服务),三个数据库ksd_sharding-db,名字相同,两个数据源ds0,ds1,ds2
    • 每个数据库下方新建ksd_user0、ksd_user1、ksd_user1即可
    • 数据库规则,result = (sex%3),result=0的放入ds2库,result=1的放入ds1库,result=2的放入ds2库
    • 数据表规则:result = (age%3),根据取模结果分别放入ksd_user0、ksd_user1、ksd_user1表
    • 如果数据库配置了主从复制,需要将主从复制取消掉
    mysql> stop slave;
    
    • 1
    server:
      port: 8085
    spring:
      main:
        allow-bean-definition-overriding: true
      shardingsphere:
        # 参数配置,显示sql
        props:
          sql:
            show: true
        # 配置数据源
        datasource:
          # 给每个数据源取别名,下面的ds1,ds2,ds3任意取名字
          names: ds0,ds1,ds2
          # 给master-ds1每个数据源配置数据库连接信息
          ds0:
            # 配置druid数据源
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://master:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 100
            minPoolSize: 5
          # 配置ds2-slave
          ds1:
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://slave1:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 10
            minPoolSize: 5
          # 配置ds3-slave
          ds2:
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://slave2:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 10
            minPoolSize: 5
        # 配置默认数据源ds1
        sharding:
          # 默认数据源,主要用于写,注意一定要配置读写分离 ,注意:如果不配置,那么就会把三个节点都当做从slave节点,新增,修改和删除会出错。
          default-data-source-name: ds0
          # 配置分表的规则
          tables:
            # ksd_user 逻辑表名
            ksd_user:
              key-generator:
                # 主键的列明,雪花算法,也可以是UUID
                column: id
                type: SNOWFLAKE
              # 数据节点:数据源$->{0..N}.逻辑表名$->{0..N}
              actual-data-nodes: ds$->{0..2}.ksd_user$->{0..2}
              # 拆分库策略,也就是什么样子的数据放入放到哪个数据库中。
              database-strategy:
                inline:
                  sharding-column: sex    # 分片字段(分片键)
                  algorithm-expression: ds$->{sex % 3} # 分片算法表达式
              # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
              table-strategy:
                inline:
                  sharding-column: age    # 分片字段(分片键)
                  algorithm-expression: ksd_user$->{age % 3} # 分片算法表达式
    # 整合mybatis的配置XXXXX
    mybatis:
      mapper-locations: classpath:mapper/*.xml
      type-aliases-package: com.example.shardingjdbc.sharding.entity
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    
    
        @GetMapping("/save")
        public String insert() {
    
            User user = new User();
            user.setNickname("test" + new Random().nextInt());
            user.setBirthday(new Date());
            // 3%3=0,所以这条数据应该在ds0这台服务上
            user.setSex(3);
            // 25%3=1  所以这个条数据应该在ksd_user1这个表里面
            user.setAge(25);
            user.setPassword("123456");
            userMapper.addUser(user);
            return "success";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    二、根据实时间日期 - 按照标准规则分库分表

    标准分片 - Standard

    • 对应StrandardShardingStrategy.提供对SQL语句中的=,in和恶between and 的分片操作支持
    • StrandardShardingStrategy只支持分片键。提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法
    • PreciseShardingAlgorithm是必选的,用于处理=和IN的分片
    • RangeShardingAlgorithm是可选的,是用于处理Betwwen and分片,如果不配置和RangeShardingAlgorithm,SQL的Between AND 将按照全库路由处理

    完整案例和配置如下

    yml配置

    server:
      port: 8085
    spring:
      main:
        allow-bean-definition-overriding: true
      shardingsphere:
        # 参数配置,显示sql
        props:
          sql:
            show: true
        # 配置数据源
        datasource:
          # 给每个数据源取别名,下面的ds1,ds2,ds3任意取名字
          names: ds0,ds1,ds2
          # 给master-ds1每个数据源配置数据库连接信息
          ds0:
            # 配置druid数据源
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://master:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 100
            minPoolSize: 5
          # 配置ds2-slave
          ds1:
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://slave1:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 10
            minPoolSize: 5
          # 配置ds3-slave
          ds2:
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url: jdbc:mysql://slave2:port/ksd-sharding-db?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
            username: root
            password: 123456
            maxPoolSize: 10
            minPoolSize: 5
        # 配置默认数据源ds1
        sharding:
          # 默认数据源,主要用于写,注意一定要配置读写分离 ,注意:如果不配置,那么就会把三个节点都当做从slave节点,新增,修改和删除会出错。
          default-data-source-name: ds0
          # 配置分表的规则
          tables:
            # ksd_user 逻辑表名
            ksd_user:
              key-generator:
                # 主键的列明,雪花算法,也可以是UUID
                column: id
                type: SNOWFLAKE
              # 数据节点:数据源$->{0..N}.逻辑表名$->{0..N}
              actual-data-nodes: ds$->{0..2}.ksd_user$->{0..2}
              # 拆分库策略,也就是什么样子的数据放入放到哪个数据库中。
              database-strategy:
                standard:
                  sharding-column: birthday    # 分片字段(分片键)
                  preciseAlgorithmClassName: com.example.shardingjdbc.sharding.algorithm.BirthdayAlgorithm
              # 拆分表策略,也就是什么样子的数据放入放到哪个数据表中。
              table-strategy:
                inline:
                  sharding-column: age    # 分片字段(分片键)
                  algorithm-expression: ksd_user$->{age % 3} # 分片算法表达式
    # 整合mybatis的配置XXXXX
    mybatis:
      mapper-locations: classpath:mapper/*.xml
      type-aliases-package: com.example.shardingjdbc.sharding.entity
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    自定义日期规则

    
    /**
     * @description: BirthdayAlgorithm
     */
    public class BirthdayAlgorithm implements PreciseShardingAlgorithm<Date> {
        List<Date> dateList = new ArrayList<>();
        {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.set(2020, 1, 1, 0, 0, 0);
            Calendar calendar2 = Calendar.getInstance();
            calendar2.set(2021, 1, 1, 0, 0, 0);
            Calendar calendar3 = Calendar.getInstance();
            calendar3.set(2022, 1, 1, 0, 0, 0);
            dateList.add(calendar1.getTime());
            dateList.add(calendar2.getTime());
            dateList.add(calendar3.getTime());
        }
        @Override
        public String doSharding(Collection<String> collection, PreciseShardingValue<Date> preciseShardingValue) {
            // 获取属性 数据库中的值
            Date date = preciseShardingValue.getValue();
            // 获取数据源名称列表
            Iterator<String> iterator = collection.iterator();
            String target = null;
            for (Date item: dateList
                 ) {
                target = iterator.next();
                if (date.before(item)) {
                    break;
                }
            }
            return target;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    测试结果

    • http://localhost:8085/user/save?sex=3&age=3&birthday=2020-03-09 —- ds1
      在这里插入图片描述
    • http://localhost:8085/user/save?sex=3&age=3&birthday=2021-03-09 —- ds2

    在这里插入图片描述


  • 相关阅读:
    SpringBoot邮件服务spring-boot-starter-mail
    第1章 电子设计与制作基础
    MyBatis的各种查询功能
    C#事件订阅发布实现原理详解
    【语音编码】基于matlab ADPCM编解码(Matlab代码实现)
    如何在springboot项目中删除引用jar包中的无用bean
    基于JavaSwing开发进销存管理系统的设计与实现 课程设计 大作业 毕业设计
    Lua01 基本语法+数据类型+流程控制+运算符
    二苯基环辛炔修饰CulnS2硫铟铜量子点,PbS硫化铅量子点,DBCO-CulnS2 QDs
    C++11单例模式
  • 原文地址:https://blog.csdn.net/Grady00/article/details/136393822