sharding-jdbc 实现按月分表

2023-11-11

最近生产上发现了一个大表,因为数据太多导致新增查询都很慢,考虑先对历史数据进行归档,新数据按月分表存储。使用到的框架主要是:sharding-jdbc、spring boot、mybatis、durid,先建个demo简单实践下。

首先,准备一个分片的表

CREATE TABLE `t_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `log` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `time` varchar(12) DEFAULT NULL,
  `created_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

接着,创建一个新的项目,引入相关依赖,这用的是sharding-jdbc 4.0.0-RC1版本:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>false</overwrite>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.22</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

添加配置:

# 配置存放到内存中
spring.shardingsphere.mode.type=Memory
# 打印sql日志
spring.shardingsphere.props.sql.show=true
# 配置数据源
spring.shardingsphere.datasource.names=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://192.168.3.4:3306/sharding?autoReconnect=true&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=root

# 配置数据节点,这里是按月分表,时间范围设置在202201 ~ 210012
spring.shardingsphere.sharding.tables.t_log.actual-data-nodes=ds.t_log_$->{2022..2100}0$->{1..9},ds.t_log_$->{2022..2100}1$->{0..2}
# 使用标准分片策略,配置分片字段
spring.shardingsphere.sharding.tables.t_log.table-strategy.standard.sharding-column=time
# 配置精确、范围查询分片算法
spring.shardingsphere.sharding.tables.t_log.table-strategy.standard.precise-algorithm-class-name=com.example.springboot.algorithm.TimeShardingAlgorithm
spring.shardingsphere.sharding.tables.t_log.table-strategy.standard.range-algorithm-class-name=com.example.springboot.algorithm.TimeShardingAlgorithm
# 配置主键以及生成算法
spring.shardingsphere.sharding.tables.t_log.key-generator.column=id
spring.shardingsphere.sharding.tables.t_log.key-generator.type=SNOWFLAKE

这里要注意下precise-algorithm是配置精确分片算法实现类(如=、in),range-algorithm是配置范围分片算法实现类(如between and),实现如下:

package com.example.springboot.algorithm;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 分片算法,按月分片
 */
public class TimeShardingAlgorithm implements PreciseShardingAlgorithm<String>, RangeShardingAlgorithm<String> {

    /**
     * 需要空构造方法
     */
    public TimeShardingAlgorithm() {}

    /**
     * 时间格式
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    /**
     * 精确分片
     * @param collection
     * @param preciseShardingValue
     * @return
     */
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        return buildShardingTable(preciseShardingValue.getLogicTableName(), preciseShardingValue.getValue());
    }

    /**
     * 构建分片后的表名
     * @param logicTableName
     * @param date
     * @return
     */
    private String buildShardingTable(String logicTableName, String date) {
        StringBuffer stringBuffer = new StringBuffer(logicTableName).append("_").append(date, 0, 6);
        return stringBuffer.toString();
    }

    /**
     * 范围分片
     * @param collection
     * @param rangeShardingValue
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        Range<String> valueRange = rangeShardingValue.getValueRange();
        String lower = valueRange.lowerEndpoint();
        String upper = valueRange.upperEndpoint();

        LocalDate start = LocalDate.parse(lower, DATE_TIME_FORMATTER);
        LocalDate end = LocalDate.parse(upper, DATE_TIME_FORMATTER);

        Collection<String> tables = new ArrayList<>();
        while (start.compareTo(end) <= 0) {
            tables.add(buildShardingTable(rangeShardingValue.getLogicTableName(), start.format(DATE_TIME_FORMATTER)));
            start = start.plusMonths(1L);
        }
        
        // collection配置的数据节点表,这里是排除不存在配置中的表
        collection.retainAll(tables);
        return collection;
    }

}

添加一个controller进行测试:

package com.example.springboot.controller;

import com.example.springboot.bean.log.Log;
import com.example.springboot.bean.log.LogExample;
import com.example.springboot.service.ILogService;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@RestController
public class LonController {

    @Autowired
    private ILogService logService;

    /**
     * 测试新增
     * @param logStr
     * @return
     */
    @RequestMapping("/insert")
    public Object insert(String logStr) {
        Log log = new Log();
        log.setTime(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        log.setLog(logStr);
        log.setCreatedTime(new Date());
        return logService.insertSelective(log);
    }

    /**
     * 测试批量新增
     * @return
     */
    @RequestMapping("/inserts")
    public Object insert() {
        Log log = new Log();
//        log.setTime(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        log.setTime("202203");
        log.setLog("inserts 1");
        log.setCreatedTime(new Date());
        Log log1 = new Log();
//        log1.setTime(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        log1.setTime("202202");
        log1.setLog("inserts 2");
        log1.setCreatedTime(new Date());
        Log log2 = new Log();
        log2.setTime("202202");
        log2.setLog("inserts 3");
        log2.setCreatedTime(new Date());
        List<Log> lists = Lists.newArrayList(log, log1, log2);
        logService.insertBatch(lists);
        return lists;
    }

    /**
     * 测试删除
     * @param id
     * @return
     */
    @RequestMapping("/delete")
    public Object delete(Long id) {
        return logService.deleteByPrimaryKey(id);
    }

    /**
     * 测试查询
     * @param id
     * @return
     */
    @RequestMapping("/select")
    public Object select(Long id) {
        return logService.selectByPrimaryKey(id);
    }

    /**
     * 按分片字段查询
     * @param time
     * @return
     */
    @RequestMapping("/selects")
    public Object selects(String time) {
        LogExample example = new LogExample();
        example.createCriteria().andTimeEqualTo(time);
        return logService.selectByExample(example);
    }

    /**
     * 范围查询
     * @param times
     * @param timee
     * @return
     */
    @RequestMapping("/selectr")
    public Object selectr(String times, String timee) {
        LogExample example = new LogExample();
        example.createCriteria().andTimeBetween(times, timee);
        return logService.selectByExample(example);
    }

    /**
     * 更新
     * @param id
     * @return
     */
    @RequestMapping("/update")
    public Object update(Long id) {
        Log log = new Log();
        log.setId(id);
        log.setTime(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        log.setLog("updated");
        log.setCreatedTime(new Date());
        return logService.updateByPrimaryKeySelective(log);
    }

}

最后调用接口进行测试,控制台会打印逻辑SQL以及实际上执行的SQL,如下:

http://127.0.0.1:8081/insert?logStr=test

 注意,where语句要包含分片字段,才会由分片算法进行分片,如果不包含则会查询全部数据节点。其它的,表可以先建好,或者写个定时器每个月最后一天建下个月的表。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

sharding-jdbc 实现按月分表 的相关文章

随机推荐

  • sizeof与strlen使用中的问题

    概述 直接上代码 使用中经常会涉及到sizeof与strlen计算的问题 下面看例子 char pstr hello char pstr hellonini char pstr 6 hello 上述求sizeof pstr 的值 分别为 4
  • python中获取指定目录下所有文件名列表的程序

    http blog csdn net rumswell article details 9818001 coding utf 8 module wlab Filename wgetfilelist py Function def IsSub
  • 开发团队工作中遇到的问题复盘

    来到团队中20多天了 其实整体是不顺利的 1 团队开发效率还需要提高 没有达到预期的想法 2 有几次忙乱了心 把本身简单的事情处理复杂了 增加了团队成员和公司的对立 3 自己的工作内容变多了 总是感觉有很多事忙不完 又不能刷刷刷马上解决掉
  • JS逆向——建筑市场监管公共服务平台

    全国建筑市场监管公共服务平台 四库一平台 问题 1 接口返回值加密 1 接口返回的数据为加密后的文本 先根据密文长度无法直接判断具体的加密方式 2 个人比较喜欢用hook 所以先对几个常用的加解密函数进行hook 并进行控制台输出 hook
  • QT基本使用

    目录 一 QWidget QDialog QMainWIndow的异同点 二 信号与槽 1 信号与槽 2 自动关联信号与槽 3 自定义信号与槽 设定槽 设定信号 四 模态 非模态窗口 1 新窗口的创建 2 模态 非模态窗口的创建 五 加载资
  • 程序员求职之道(《程序员面试笔试宝典》)之面试笔试技巧?

    不是看了本C语言编程书籍 就可以说精通C语言 会写一句hello world 就可以自称程序员 程序员是一种职业 更是一种精神 他们天资聪颖 不拘小节 他们个性十足 幽默风趣 他们工作努力 任劳任怨 他们是21世纪最可爱的人 选择程序员作为
  • 需求着急上线,是写烂代码的理由吗?

    软件开发大师Martin Fowler说过 Any fool can write code that a computer can understand Good programmers write code that humans can
  • C++学习笔记(三)--继承中的异常处理

    继承中的异常处理 include
  • Docker部署seata Nacos作为注册配置中心

    Docker部署seata Nacos作为注册配置中心 一 Seata服务端安装 一 Seata clint使用 一 Seata服务端安装 1 1 要注意和spring cloud boot alibaba等版本对应上 避免出现版本不兼容问
  • 开源项目:ZXing(三)二维码解码

    继续上一节的内容 本节我们将对上一节的QQ群号二维码进行解码 QQ群号二维码图片另存为后 将下载的 jpg拷贝到项目assets目录下 1 解码配置 Map
  • JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

    JavaWeb Servlet Tomcat工作机制动画演示 点击动图可全屏观看 什么是Servlet Servlet Server Applet 全称Java Servlet 未有中文译文 是用Java编写的服务器端程序 其主要功能在于交
  • netbeans6.0 javafx 插件安装

    netbeans6 0 beta1已经发布有一段时间了 netbeans现在确实是越来越好了 随着新版本的发布 我们也应该来熟悉一下这个好产品 javafx自从2007javaone sun公布以来 一直收到热捧 今天我们来看看netbea
  • Platt SMO算法

    Platt SMO算法 1996年 John Platt 发布了一个称为SMO的强大算法 用于训练SVM SMO表示序列最小优化 SequentialMinimal Optimization Platt 的 SMO 算法是将大优化问题分解为
  • 涂抹CANVAS,判断清除完毕执行操作

    涂抹CANVAS 判断清除完毕执行操作 clearCanvas js代码如下 如清除时断续将 for var i 0 i lt Math round Math PI r i 5 改为 for var i 0 i lt Math round
  • 2021美赛D题

    2021年ICM问题D 音乐的影响 音乐自古以来就是人类社会的一部分 是文化遗产的重要组成部分 为了理解音乐在人类集体经验中所扮演的角色 我们被要求开发一种量化音乐进化的方法 当艺术家创作一首新的音乐作品时 有许多因素会影响他们 包括他们与
  • miscellany-在idea里创建properties文件

    在idea里创建properties文件 在resources里创建即可
  • C++this指针

    C this指针 this是C 中的一个关键字 也是一个const指针 它指向当前对象 通过它可以访问当前对象的所有成员 例如 class A private char name public void show cout lt lt he
  • ubuntu22.04安装YouCompleteMe

    先建一个文件夹 sudo mkdir vim bundle 然后进入这个文件夹 hunter hunter desktop vim bundle ls command t sparkup vim fugitive Vundle vim 接下
  • Qt入门超级简单小项目(3)布局管理器

    环境 Windows10 Qt5 完善菜单 1 新建Qt Widgets应用 项目名称为myMainWindow1 基类选择QMainWindow 类名为MainWindow 2 完成后 在设计模式添加菜单项 并添加资源文件 向其中添加菜单
  • sharding-jdbc 实现按月分表

    最近生产上发现了一个大表 因为数据太多导致新增查询都很慢 考虑先对历史数据进行归档 新数据按月分表存储 使用到的框架主要是 sharding jdbc spring boot mybatis durid 先建个demo简单实践下 首先 准备