ShardingJdbc实战-分库分表

文章目录


基本配置

逻辑表

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

在shardingjdbc中的定义方式如下:

yaml 复制代码
spring:
  shardingsphere:
    sharding:
      tables:
        # ksd_user 逻辑表名
        ksd_user:

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

yaml 复制代码
 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,

寻找规则如下

分库分表的分片策略

分片策略由分片键和分片算法组成

一、inline 行表达时分片策略

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

yaml 复制代码
    # 配置默认数据源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} # 分片算法表达式

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表
  • 如果数据库配置了主从复制,需要将主从复制取消掉
powershell 复制代码
mysql> stop slave;
yaml 复制代码
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
java 复制代码
    @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";
    }

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

标准分片 - Standard

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

完整案例和配置如下

yml配置

yaml 复制代码
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

自定义日期规则

java 复制代码
/**
 * @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;
    }
}

测试结果


相关推荐
暗黑起源喵2 分钟前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong7 分钟前
Java反射
java·开发语言·反射
九圣残炎40 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
wclass-zhengge42 分钟前
Netty篇(入门编程)
java·linux·服务器
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
雷神乐乐1 小时前
Maven学习——创建Maven的Java和Web工程,并运行在Tomcat上
java·maven
码农派大星。1 小时前
Spring Boot 配置文件
java·spring boot·后端
顾北川_野1 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
江深竹静,一苇以航1 小时前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
confiself2 小时前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言