开启成长之旅!这是我参与「日新计划 12 月更文挑战」的第20天,点击检查活动概况

话不多说,直接开始。

一、引入依靠

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.2</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

二、yml装备

包含数据源装备、数据节点装备、分片战略装备、主键生成战略等装备

server:
  port: 9088
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://localhost:3306/order?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
        username: root
        password: root
      ds1:
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
        username: root
        password: root
    enabled: true
    mode:
      type: memory
    props:
      sql-show: true
    rules:
      sharding:
        default-key-generate-strategy:
          column: id
        key-generators:
          id-key:
            type: SNOWFLAKE
        tables:
          # 需求分表的逻辑表名, 假如需求装备多个数据表,依照这个规矩装备就可以
          test_data:
            # 表的实在表列表(需求留意这儿的表都应该存在,不然就有可能出现我第一篇文章里边说到的 NPE 异常)
            actual-data-nodes: ds0.test_data_20220${8..9}, ds0.test_data_2022${10..12}
            # 分片战略装备
            table-strategy:
              standard:
                # 分片算法是 his_month_sharding, 这个称号是在下面装备的
                sharding-algorithm-name: his_month_sharding
                # 分片列是 acquisition_time, 需求留意的是,分表算法的数据类型一定要和这个分片的列数据类型一致
                sharding-column: create_time
        # 装备分片算法
        sharding-algorithms:
          # 分片算法称号
          his_month_sharding:
            # 分片算法类型,这个type就是咱们的分片算法完成类中 getType() 的返回值,SPI适用于这种方法
            type: HIS_DATA_SPI_BASED

三、完成分片算法

这儿首要标准分片算法接口,官方保留了接口,详细算法需求自己动手完成。通过分片键create_time完成规模查找和准确查找。


@Slf4j
public class TstDataMonthShardingAlgorithm implements StandardShardingAlgorithm<Date> {
    private final ThreadLocal<SimpleDateFormat> formatThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMM"));
    private Properties props;
    /**
     * 设置该参数的原因是,假如在规模查找的时分咱们没有设置最小值,比如下面的查询
     * where acquisition_time < '2022-08-11 00:00:00'
     * 这个时分规模查找就只有上限而没有下限,这时分就需求有一个下限值兜底,不能一致遍历下去
     */
    private Date tableLowerDate;
    /**
     *
     * @param availableTargetNames 可用的表列表(装备文件中装备的 actual-data-nodes会被解析成 列表被传递过来)
     * @param shardingValue        准确的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
        Date value = shardingValue.getValue();
        // 依据准确值获取路由
        String actuallyTableName = shardingValue.getLogicTableName() + shardingSuffix(value);
        if (availableTargetNames.contains(actuallyTableName)) {
            return actuallyTableName;
        }
        return null;
    }
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {
        // 获取到规模查找的最小值,假如条件中没有最小值设置为 tableLowerDate
        Date rangeLowerDate;
        if (shardingValue.getValueRange().hasLowerBound()) {
            rangeLowerDate = shardingValue.getValueRange().lowerEndpoint();
        } else {
            rangeLowerDate = tableLowerDate;
        }
        // 获取到规模查找的最大值,假如没有装备最大值,设置为当时时间 + 1 月
        // 这儿需求留意,你的项目里边这样做是否合理
        Date rangeUpperDate;
        if (shardingValue.getValueRange().hasUpperBound()) {
            rangeUpperDate = shardingValue.getValueRange().upperEndpoint();
        } else {
            // 往后延一个月
            rangeUpperDate = DateUtil.offsetMonth(new Date(), 1);
        }
        rangeUpperDate = DateUtil.endOfMonth(rangeUpperDate);
        List<String> tableNames = new ArrayList<>();
        // 过滤那些存在的表
        while (rangeLowerDate.before(rangeUpperDate)) {
            String actuallyTableName = shardingValue.getLogicTableName() + shardingSuffix(rangeLowerDate);
            if (availableTargetNames.contains(actuallyTableName)) {
                tableNames.add(actuallyTableName);
            }
            rangeLowerDate = DateUtil.offsetMonth(rangeLowerDate, 1);
        }
        return tableNames;
    }
    /**
     * sharding 表后缀 _yyyyMM
     */
    private String shardingSuffix(Date shardingValue) {
        return "_" + formatThreadLocal.get().format(shardingValue);
    }
    /**
     * SPI方法的 SPI称号,装备文件中装备的时分需求用到
     */
    @Override
    public String getType() {
        return "HIS_DATA_SPI_BASED";
    }
    @Override
    public void init(Properties properties) {
        this.props = properties;
        String autoCreateTableLowerDate = properties.getProperty("auto-create-table-lower");
        try {
            this.tableLowerDate = formatThreadLocal.get().parse(autoCreateTableLowerDate);
        } catch (Exception e) {
            log.error("parse auto-create table lower date failed: {}, use default date 202208", e.getMessage());
            try {
                this.tableLowerDate = formatThreadLocal.get().parse("202208");
            } catch (ParseException ignored) {
            }
        }
    }
    @Override
    public Properties getProps() {
        return this.props;
    }
}

四、运用SPI注册服务

SPI全称Service Provider Interface,是Java供给的一套用来被第三方完成或者扩展的接口,它可以用来启用框架扩展和替换组件。SPI的效果就是为这些被扩展的API寻觅服务完成。

1、在resources目录下新建META-INF/services目录

    -- resources
        -- META-INF
            -- services

2、在这个目录下新建一个与上述接口的全限定名一致的文件

Sharding-jdbc实现分库分表一些尝试

3、在这个文件中写入接口的完成类的全限定名

Sharding-jdbc实现分库分表一些尝试

五、操作测验

1、新增数据,依据createTime放入不同的表 { “name”:”8月5″, “createTime”:”2022-09-05 12:00:00″ }

Sharding-jdbc实现分库分表一些尝试

2、依据ID=1600390521566187522查询数据

Sharding-jdbc实现分库分表一些尝试

3、依据日期区间查询

Sharding-jdbc实现分库分表一些尝试