使用 ShardingSphere 分表学习笔记

最近在学习使用 shardingsphere 分表,定位为轻量级 Java 框架,无需部署额外服务,引入 Jar 包即可使用;当前使用发布最新版本 4.0.0,新特性查看:ShardingSphere 4.0.0 

pom 文件引入maven依赖


    org.apache.shardingsphere
    sharding-jdbc-spring-boot-starter
    4.0.0





	com.alibaba
	druid
	${druid-version}

1.1.10 ,这里使用的是 sharding-jdbc-spring-boot-starter,也可以使用 sharding-jdbc-core,版本号一致即可

 

YML 文件配置(也可以使用 Java 代码配置):

     1. 数据源配置

spring:
  shardingsphere:
    # 数据源配置
    datasource:
      names: ds0  # ,ds1 
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ds0name
        username: root
        password: xxxx
       # other params
    # 多数据源
      #ds1:
      #  type: com.alibaba.druid.pool.DruidDataSource
      #  driver-class-name: com.mysql.jdbc.Driver
      #  url: jdbc:mysql://localhost:3306/ds1name
      #  username: root
      #  password: xxxx

我配置的是单数据源分表,也可指定多数据源进行分库策略 or 主从策略

 

      2. 表分片策略

          2.1 主键/ID字段分片

    sharding:
      tables:
        sys_user: # 逻辑表
          actual-data-nodes: ds0.sys_user_$->{0..9} # 表数量配置
          table-strategy:
            inline:
              sharding-column: user_id # 分片键
              algorithm-expression: sys_user_$->{user_id % 10} # 根据 user_id 取模分表
          key-generator: #  user_id 生成策略
            column: user_id
            type: SNOWFLAKE
     #  sys_xxx # 其他表分片

sys_user 是逻辑表名称,分表后创建的表应该是 sys_user_number

actual-data-nodes 是数据节点由数据源和数据表组成,也就是真实表,使用 行表达式  {0..10} 表示有 sys_user_0 到 sys_user_9 共 十张表;shardingsphere 不会自动创建表,需要使用 脚本定时 或 手动提前创建好

table-strategy 是 分片策略,根据需求实现具体的分片策略,inline 为行表达式,standard 为自定义分片

algorithm-expression 是算法表达式,根据 user_id 取模尾数为 n 的路由到后缀为 n 的表中(sys_user_n)

key-generator 是主键生成,SNOWFLAKE 是Twitter的分布式 ID 生成算法

          2.2 时间字段分片(如日志表)

sharding:
      tables:
        sys_log: # 逻辑表
          actual-data-nodes: ds0.sys_log_20200116 # 默认表配置
          table-strategy:
            standard:
              sharding-column: log_time # 分片列
              preciseAlgorithmClassName: pers.allen.demo.config.SysLogDataTableShardingAlgorithm # 精确分片
              rangeAlgorithmClassName:  pers.allen.demo.config.SysLogDataTableRangeShardingAlgorithm # 范围分片
          key-generator: #  id 生成策略
            column: id
            type: SNOWFLAKE

preciseAlgorithmClassName 和 rangeAlgorithmClassName 为分片支持和实现请查看 分片算法 ,下面是按天分片实现,按月分片只需要改动部分代码即可

代码如下:

/**
 * 通用部分
 */
public class SysLogDataTableSharding {

    //
    protected static final String UNDERLINE = "_";
    // cure_time 日期格式
    protected static final DateTimeFormatter dtfTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    protected static final DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("yyyyMMdd");

    protected static String spliceTableName(String logicTableName,String date) {
        StringBuilder tableName = new StringBuilder();
        tableName.append(logicTableName).append(UNDERLINE).append(date);
        return tableName.toString();
    }

}

 

/**
 * 精确分片
 * PreciseShardingAlgorithm:用于处理使用单一键作为分片键的=与IN进行分片的场景
 * Created by lengyul on 2020/1/8 10:11
 */
public class SysLogDataTableShardingAlgorithm extends SysLogDataTableSharding implements PreciseShardingAlgorithm {

    @Override
    public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
        // 逻辑表名称
        String logicTableName = preciseShardingValue.getLogicTableName();
        // cure_time = preciseShardingValue.getValue();
        String cure_time = preciseShardingValue.getValue();
        // 将时间字符串转换为日期类型
        LocalDate parseDate = LocalDate.parse(cure_time, dtfTime);
        // 获取日期 yyyyMMdd
        String yyyyMMdd = parseDate.format(dtfDate);
        // 实际表名称
        String realTableName = spliceTableName(logicTableName,yyyyMMdd);
        System.out.println(realTableName);
        return realTableName;
    }

}
/**
 * 范围分片
 * RangeShardingAlgorithm:用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景
 * Created by lengyul on 2020/1/8 15:06
 */
public class SysLogDataTableRangeShardingAlgorithm extends SysLogDataTableSharding implements RangeShardingAlgorithm {

    @Override
    public Collection doSharding(Collection collection, RangeShardingValue rangeShardingValue) {
        // 逻辑表名称
        String logicTableName = rangeShardingValue.getLogicTableName();
        Range ranges = rangeShardingValue.getValueRange();
        // 获取时间范围
        try {
            String lower = ranges.lowerEndpoint();
            String upper = ranges.upperEndpoint();
            LocalDateTime startTime = LocalDateTime.parse(lower,dtfTime);
            LocalDateTime endTime = LocalDateTime.parse(upper,dtfTime);
            Collection rangeTables = getRangeTables(logicTableName,startTime, endTime);
            System.out.println(rangeTables);
            return rangeTables;
        } catch (Exception e) {
            e.printStackTrace();;
        }
        return collection;
    }
    
    /**
     * LocalDateTime 计算时间表范围
     * @param logicTableName
     * @param startTime
     * @param endTime
     * @return
     */
    private static Collection getRangeTables(String logicTableName,LocalDateTime startTime, LocalDateTime endTime) {
        Collection tables = new LinkedHashSet<>();
        while(startTime.isBefore(endTime)) {
            String yyyyMMdd = startTime.toLocalDate().format(dtfDate);
            String realTableName = spliceTableName(logicTableName,yyyyMMdd);
            tables.add(realTableName);
            startTime = startTime.plusDays(1);
        }
        /*当 startTime 的 HH:mm:ss 大于 endTime 时,day + 1 会出现 startTime 大于 endTime
        导致 endTime 对应的表没有添加到 tables 列表中 */
        String endDate = endTime.toLocalDate().format(dtfDate);
        String lastTable = spliceTableName(logicTableName,endDate);
        if(!tables.contains(lastTable)) {
            tables.add(lastTable);
        }
        return tables;
    }

关于查询:

  •  分片后,如果查询 where 条件没有带分片字段的话会去扫描配置的所有真实数据表 = actual-data-nodes,最后将匹配到的数据合并为一个结果集返回,保存数据时找不到对应的表会报表不存在
  •  复杂SQL或者UNION可能会不支持,具体 SQL使用规范

 

遇到问题记录:

ShardingSphere 4.0.0-RC3 之前的版本 MySQL NOW()   被解析为字符串 "NOW()",导致保存时间字段失败

ShardingSphere 4.0.0 + druid-spring-boot-starter 启动初始化数据源找不到 "url",具体原因:可能是 druid-spring-boot-starter 会去构建数据源,换为 druid 即可解决

 

你可能感兴趣的:(Java中间件技术,shardingsphere,分表)