跳至主要內容

时间分表

xuejmnet大约 2 分钟

本章节我们实现分库分表的分表功能,实现按时间分表,按月份表

这是我们最终的java对象


@Data
@Table(value = "t_topic_sharding_time",shardingInitializer = TopicShardingTimeShardingInitializer.class)
public class TopicShardingTime {

    @Column(primaryKey = true)
    private String id;
    private Integer stars;
    private String title;
    @ShardingTableKey
    private LocalDateTime createTime;
}



public class TopicShardingTimeShardingInitializer extends AbstractShardingMonthInitializer<TopicShardingTime> {

    @Override
    protected LocalDateTime getBeginTime() {
        return LocalDateTime.of(2020, 1, 1, 1, 1);
    }

    @Override
    protected LocalDateTime getEndTime() {
        return LocalDateTime.now();
    }


    @Override
    public void configure0(ShardingEntityBuilder<TopicShardingTime> builder) {


    }
}

配置对象

首先我们来看下对象

@Data
@Table(value = "t_topic_sharding_time")
public class TopicShardingTime {

    @Column(primaryKey = true)
    //@ShardingExtraTableKey 先忽略该注解
    private String id;
    private Integer stars;
    private String title;
    @ShardingTableKey //表示这个属性为分表键
    private LocalDateTime createTime;
}

注解Table属性shardingInitializer = TopicShardingTimeShardingInitializer.class表示分初始化器使用TopicShardingTimeShardingInitializer.class



public class TopicShardingTimeShardingInitializer extends AbstractShardingMonthInitializer<TopicShardingTime> {

    //表示初始化时的开始时间用来初始化自动计算数据库的分片数量
    @Override
    protected LocalDateTime getBeginTime() {
        return LocalDateTime.of(2020, 1, 1, 1, 1);
    }

    //结束时间,即TopicShardingTime第一次被初始化时和getBeginTime互相计算出现在数据库的分片数量
    @Override
    protected LocalDateTime getEndTime() {
        return LocalDateTime.now();
    }


    @Override
    public void configure0(ShardingEntityBuilder<TopicShardingTime> builder) {


    }
}

这样我们就完成了对象的分片配置,具体原理是为什么呢?
首先我们通过设置beginTimeendTime在初次使用TopicShardingTime对象的时候确保可以计算出对应的数据库应有的db数量,具体代码在AbstractShardingMonthInitializer这个默认的分片初始化器里面

 @Override
    public void configure(ShardingEntityBuilder<T> builder) {
        EntityMetadata entityMetadata = builder.getEntityMetadata();
        EasyQueryOption easyQueryOption = builder.getEasyQueryOption();
        String defaultDataSourceName = easyQueryOption.getDefaultDataSourceName();
        String tableName = entityMetadata.getTableName();
        //防止系统在凌晨发布定时任务刚好在23:59:00-00:00:00时间点运行过,导致下次运行会在00:00:01-59,会缺几秒导致没有加到内存中所以需要加5分钟
        LocalDateTime setBeginTime = getBeginTime().plusMinutes(5);

        LocalDateTime beginTime = getBeginTimeToStart(setBeginTime);
        LocalDateTime endTime = getEndTime();
        if (beginTime.isAfter(endTime)) {
            throw new IllegalArgumentException("begin time:" + beginTime + " is after end time:" + endTime);
        }
        String tableSeparator = getTableSeparator();

        LinkedHashMap<String, Collection<String>> initTables = new LinkedHashMap<>();
        //应该是不在endTime后可以等于endTime
        while (!beginTime.isAfter(endTime)) {
            String dataSource = formatDataSource(beginTime, defaultDataSourceName);
            String tail = formatTail(beginTime);
            Collection<String> actualTableNames = EasyMapUtil.computeIfAbsent(initTables,dataSource, key -> new ArrayList<>());
            actualTableNames.add(tableName + tableSeparator + tail);
            beginTime = getNextTime(beginTime);
        }

        //初始化实际表
        builder.actualTableNameInit(initTables);
        configure0(builder);
    }

配置路由


public class TopicShardingTimeTableRoute extends AbstractMonthTableRoute<TopicShardingTime> {

    @Override
    protected LocalDateTime convertLocalDateTime(Object shardingValue) {
        return (LocalDateTime)shardingValue;
    }
}

通过继承默认抽象路由AbstractMonthTableRoute我们非常简单的实现了分片的规则


        EasyQueryClient easyQueryClient = EasyQueryBootstrapper.defaultBuilderConfiguration()
                .setDefaultDataSource(dataSource)
                .optionConfigure(op -> {
                    op.setDeleteThrowError(false);
                    op.setExecutorCorePoolSize(1);
                    op.setExecutorMaximumPoolSize(0);
                    op.setMaxShardingQueryLimit(10);
                    op.setThrowIfRouteNotMatch(false);
                    op.setMaxShardingRouteCount(512);
                    op.setDefaultDataSourceMergePoolSize(20);
                    //开启定时任务 不然明天的表或者下个月的表不会在内存中存在
                    op.setStartTimeJob(true);
                    op.setReverseOffsetThreshold(10);
                })
                .useDatabaseConfigure(new MySQLDatabaseConfiguration())
                .build();
        DefaultEasyEntityQuery easyEntityQuery = new DefaultEasyEntityQuery(easyQueryClient);
        QueryRuntimeContext runtimeContext = easyQuery.getRuntimeContext();
        QueryConfiguration configuration = runtimeContext.getQueryConfiguration();
        configuration.applyShardingInitializer(new TopicShardingTimeShardingInitializer());
        TableRouteManager tableRouteManager = runtimeContext.getTableRouteManager();
        tableRouteManager.addRoute(new TopicShardingTimeTableRoute());

配置ShardingInitializer和添加路由即可

上次编辑于:
贡献者: Hoysing