sharding-jdbc 按月份分表

<!--sharding-jdbc -->
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!--sharding-jdbc结束-->

sharding-jdbc 按月份分表须要本身实现。须要实现两个接口PreciseShardingAlgorithm,RangeShardingAlgorithm(还没实现)。并在配置文件里添加实现路径
以下:com.simianBook.conf.TimeShardingTableAlgorithm
TimeShardingTableAlgorithm路径
那么yml 里的配置路径以下java

sharding:
  jdbc:
    datasource:
      names: user-0,user-1
      user-0:   #springboot  在yml 配置里key不支持 '_'  推荐使用'-'
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/t_user_0?characterEncoding=UTF-8&serverTimezone=GMT
        username: root
        password: hou1147646079
      user-1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/t_user_1?characterEncoding=UTF-8&serverTimezone=GMT
        username: root
        password: hou1147646079
    config:
      sharding: #分片
        default-database-strategy:
          inline:
            sharding-column: user_id
            algorithm-expression: user ->${user_id % 2}
        props:
          sql.show: true
        tables:
          user:
            key-generator-column-name: user_id #user 表的主键
            database-strategy:
              inline:
                shardingColumn: user_id  #数据库分片测略
                algorithm-expression: user-${user_id % 2} #
 #           actual-data-nodes: user-${0..1}.user_${0..1} #设置的datasource 的名字 如user-0,user-1,user_${0..1} 数据库中的
            table-strategy:
              standard: # 单列sharidng算法,须要配合对应的preciseShardingAlgorithm,rangeShardingAlgorithm接口的实现使用,目前无生产可用实现
                shardingColumn: user_id # 列名,容许单列
                precise-algorithm-class-name: com.simianBook.config.TimeShardingTableAlgorithm # preciseShardingAlgorithm接口的实现类
            #    rangeShardingAlgorithm: # rangeShardingAlgorithm接口的实现类
#              inline:
#                sharding-column: user_id
#                algorithm-expression: user_${user_id % 2}
    defaultTableStrategy:
      none:
    defaultKeyGenerator:
      type: SNOWFLAKE

下面须要来编写按月分表的方法node

package com.simianBook.config;


import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import java.text.SimpleDateFormat;
import java.util.Collection;


public class TimeShardingTableAlgorithm implements PreciseShardingAlgorithm<Long> {
   private SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMM");
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        StringBuffer tableName = new StringBuffer();
        tableName.append(shardingValue.getLogicTableName())
                 .append("_").append(getTime(shardingValue.getValue()));

        return tableName.toString();
    }
    public String getTime(long shardingKey){
        return  dateformat.format(DefaultKeyGenerator.EPOCH+(Long.valueOf(shardingKey+"")>>22));
    }


}

我是使用sharding-jdbc 自带的雪花算法 来生成主键的,雪花算法的实现逻辑
所以我在获得分片键时对分片键进行逆推能够推出分片键的时间戳。再根据时间戳获得建立此条数据建立的年月进而定位到那个表位置(或者说表名)
DefaultKeyGenerator.EPOCH+(Long.valueOf(shardingKey+"")>>22)
DefaultKeyGenerator.EPOCH 表示起始时间。在雪花算法当中生成的时间戳须要减去起始时间在进行左移22位在进行或运算
sharding-jdbc 的雪花实现方法以下 版本3.0 该版本有bug 并发量低的时候生成的分片键始终为偶数mysql

public synchronized Number generateKey() {
        long currentMillis = timeService.getCurrentMillis();
        Preconditions.checkState(this.lastTime <= currentMillis, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", new Object[]{this.lastTime, currentMillis});
        if (this.lastTime == currentMillis) { //最新时间与当前时间相同(发生并发)
            // //sequence+1  若是suquence&4095L==0时条件成立时 
            if (0L == (this.sequence = this.sequence + 1L & 4095L)) {
                currentMillis = this.waitUntilNextTime(currentMillis);//获取最新时间
            }
        } else {
            this.sequence = 0L;  //此处有bug 并发量低的时候this.sequence始终为0L的
        }

        this.lastTime = currentMillis;
        return currentMillis - EPOCH << 22 | workerId << 12 | this.sequence;
    }

3.1.0 版本解决了 本身能够看一下有什么不一样web

public synchronized Number generateKey() {
        long currentMilliseconds = timeService.getCurrentMillis();
        if (this.waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {
            currentMilliseconds = timeService.getCurrentMillis();
        }

        if (this.lastMilliseconds == currentMilliseconds) {
            if (0L == (this.sequence = this.sequence + 1L & 4095L)) {
                currentMilliseconds = this.waitUntilNextTime(currentMilliseconds);
            }
        } else {
            this.vibrateSequenceOffset();
            this.sequence = (long)this.sequenceOffset;
        }

        this.lastMilliseconds = currentMilliseconds;
        return currentMilliseconds - EPOCH << 22 | workerId << 12 | this.sequence;
    }

更新RangeShardingAlgorithm 的实现算法

package com.simianBook.config;

import com.google.common.collect.Range;
import com.simianBook.tool.ParaseShardingKeyTool;
import io.shardingsphere.api.algorithm.sharding.RangeShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.RangeShardingAlgorithm;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.stream.Stream;

/**
 * 搜查多表
 * 范围搜索时(跨表)应传递时间戳并左移22位
 */
public class TimeRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    private SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMM");
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        Collection<String> result = new LinkedHashSet<String>();
        Range<Long> shardingKey = shardingValue.getValueRange();
        long startShardingKey = shardingKey.lowerEndpoint();
        long endShardingKey = shardingKey.upperEndpoint();
        String startTimeString = ParaseShardingKeyTool.getYearAndMonth(startShardingKey);//获取到开始时间戳
        String endTimeString = ParaseShardingKeyTool.getYearAndMonth(endShardingKey);//获取结束时间戳
        Calendar cal = Calendar.getInstance();
        Date startTime = new Date(dateformat.format(startTimeString));//获取开始的年月
        Date endTime = new Date(dateformat.format(endTimeString));//获取结束的年月
        while(startTime.getTime() < endTime.getTime()){ //进行判断 获取跨月份的表 如201901,201902,201903 三个月的表
            StringBuffer tableName = new StringBuffer();
            tableName.append(shardingValue.getLogicTableName())
                    .append("_").append(dateformat.format(startTime));
            result.add(tableName.toString());
        }
        return result;
    }
}

ParaseShardingKeyToolspring

package com.simianBook.tool;

import io.shardingsphere.core.keygen.DefaultKeyGenerator;

import java.text.SimpleDateFormat;

public class ParaseShardingKeyTool {
    private static  SimpleDateFormat yearAndMonth = new SimpleDateFormat("yyyyMM");
    private static  SimpleDateFormat year = new SimpleDateFormat("yyyy");
    public static String getYearAndMonth(long shardingKey){
        return  yearAndMonth.format(DefaultKeyGenerator.EPOCH+(Long.valueOf(shardingKey+"")>>22));
    }
    public static String getYear(long shardingKey){
        return  year.format(DefaultKeyGenerator.EPOCH+(Long.valueOf(shardingKey+"")>>22));
    }
}