Spring Boot + ShardingSphere 介绍

目录

  • 前言
  • [一、为什么需要 ShardingSphere](#一、为什么需要 ShardingSphere)
  • [二、什么是 ShardingSphere](#二、什么是 ShardingSphere)
  • [三、ShardingSphere 解决了什么问题](#三、ShardingSphere 解决了什么问题)
  • [四、ShardingSphere 的核心概念](#四、ShardingSphere 的核心概念)
    • [1. 逻辑表](#1. 逻辑表)
    • [2. 真实表](#2. 真实表)
    • [3. 分片键](#3. 分片键)
    • [4. 分片算法](#4. 分片算法)
  • [五、Spring Boot 集成 ShardingSphere](#五、Spring Boot 集成 ShardingSphere)
    • [1. 引入依赖](#1. 引入依赖)
    • [2. 配置数据源](#2. 配置数据源)
    • [3. 是否还需要 spring.datasource](#3. 是否还需要 spring.datasource)
  • 六、配置真实表
  • 七、按月份分表
    • [1. 配置分片策略](#1. 配置分片策略)
    • [2. sharding-column 是什么](#2. sharding-column 是什么)
    • [3. 必须有 create_time 字段吗](#3. 必须有 create_time 字段吗)
  • 八、配置时间分片算法
    • [1. datetime-pattern](#1. datetime-pattern)
    • [2. datetime-lower](#2. datetime-lower)
    • [3. datetime-upper](#3. datetime-upper)
    • [4. sharding-suffix-pattern](#4. sharding-suffix-pattern)
    • [5. datetime-interval-unit](#5. datetime-interval-unit)
  • [九、MyBatis 和 MyBatis Plus 如何使用](#九、MyBatis 和 MyBatis Plus 如何使用)
    • [1. Mapper 不需要修改](#1. Mapper 不需要修改)
    • [2. XML 不需要修改](#2. XML 不需要修改)
    • [3. ShardingSphere 自动改写 SQL](#3. ShardingSphere 自动改写 SQL)
  • 十、查询如何路由
    • [1. 精准路由](#1. 精准路由)
    • [2. 范围路由](#2. 范围路由)
    • [3. 全路由](#3. 全路由)
  • [十一、每个 SQL 都必须带分片键吗](#十一、每个 SQL 都必须带分片键吗)
  • [十二、ShardingSphere 会自动创建表吗](#十二、ShardingSphere 会自动创建表吗)
  • 十三、如何自动创建分表
    • [1. 推荐方案](#1. 推荐方案)
    • [2. 定时任务创建](#2. 定时任务创建)
    • [3. Flyway 或 Liquibase](#3. Flyway 或 Liquibase)
  • 十四、生产环境如何设计分表
    • [1. 单纯按月份分表](#1. 单纯按月份分表)
    • [2. 按用户 Hash 分表](#2. 按用户 Hash 分表)
    • [3. 时间 + Hash](#3. 时间 + Hash)
  • [十五、ShardingSphere 的优缺点](#十五、ShardingSphere 的优缺点)
  • 十六、总结

前言

随着业务的发展,订单表、支付表、交易流水表等核心业务表的数据量会不断增长。当单表数据达到数千万甚至上亿级别时,查询性能、索引维护、数据备份和数据库扩容等问题都会逐渐显现。

为了解决单表数据量过大的问题,互联网系统通常会采用分库分表方案,将数据按照一定规则拆分到多个数据库或数据表中。然而,分库分表之后也会带来新的挑战,例如如何确定数据应该存储到哪张表、如何跨表查询数据、如何降低业务代码的改造成本等。

ShardingSphere 正是为了解决这些问题而诞生的。它能够在应用层和数据库之间提供透明的分片能力,让开发人员仍然像操作普通数据表一样进行开发,而无需关心底层的数据路由和 SQL 改写过程。

本文将结合 Spring Boot 和 MyBatis 项目,从分库分表的背景开始,逐步介绍 ShardingSphere 的核心概念、工作原理、项目集成方式、分片算法配置以及实际项目中的使用技巧,帮助读者快速掌握 ShardingSphere 的基本使用与设计思路。

shardingsphere官网

shardingsphere HitHub地址

一、为什么需要 ShardingSphere

随着业务发展,订单表、支付表、流水表的数据量会越来越大。

例如有一张支付订单表:

sql 复制代码
CREATE TABLE pay_info (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64),
    user_id BIGINT,
    amount DECIMAL(18,2),
    create_time DATETIME
);

如果每天产生 100 万条数据:

text 复制代码
100万/天
≈ 3000万/月
≈ 3.6亿/年

几年之后,单表可能达到几十亿数据。

此时会出现很多问题:

  • 查询变慢
  • 索引变大
  • 备份恢复困难
  • DDL操作耗时
  • 数据迁移困难

因此需要进行:

text 复制代码
分库分表

最常见的方案:

  • 按时间分表
  • 按用户分表
  • 按订单号分表

而目前 Java 生态中最主流的分库分表框架之一就是 Apache ShardingSphere。


二、什么是 ShardingSphere

ShardingSphere 是 Apache 顶级项目。

它是一套数据库中间件生态,主要功能包括:

  • 分库分表
  • 读写分离
  • 分布式事务
  • 数据加密
  • SQL 路由
  • SQL 改写

在 Spring Boot 项目中最常见的是:

text 复制代码
ShardingSphere-JDBC

其架构如下:

text 复制代码
MyBatis
    ↓
ShardingSphere
    ↓
MySQL

对于业务代码来说:

text 复制代码
感知不到分表的存在

三、ShardingSphere 解决了什么问题

假设数据库中有以下表:

text 复制代码
pay_info_202601
pay_info_202602
pay_info_202603
...

程序中仍然写:

sql 复制代码
select * from pay_info

或者:

java 复制代码
payInfoMapper.insert(payInfo);

增删改查时 ShardingSphere 会自动帮你改写 SQL。

例如:

java 复制代码
createTime = 2026-05-15

自动路由:

sql 复制代码
insert into pay_info_202605

开发人员完全不需要手动判断表名。


四、ShardingSphere 的核心概念

1. 逻辑表

程序中看到的表:

text 复制代码
pay_info

称为逻辑表。

例如:

sql 复制代码
select * from pay_info

2. 真实表

数据库真正存在的表:

text 复制代码
pay_info_202601
pay_info_202602
pay_info_202603

称为真实表。


3. 分片键

决定数据进入哪张表的字段。

例如:

sql 复制代码
create_time

或者:

sql 复制代码
user_id

或者:

sql 复制代码
order_no

都可以作为分片键。


4. 分片算法

根据分片键计算目标表。

例如:

java 复制代码
2026-05-15

计算得到:

text 复制代码
pay_info_202605

五、Spring Boot 集成 ShardingSphere

1. 引入依赖

xml 复制代码
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
</dependency>

2. 配置数据源

yaml 复制代码
spring:
  shardingsphere:
    datasource:
      names: ds
      ds:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test
        username: root
        password: root

这里的:

yaml 复制代码
url
username
password

就是实际数据库连接配置。


3. 是否还需要 spring.datasource

上面在 shardingsphere 下已经配置了数据源了,是否还需要 spring.datasource ?

通常不需要。

不要同时配置:

yaml 复制代码
spring:
  datasource:

和:

yaml 复制代码
spring:
  shardingsphere:
    datasource:

否则可能出现:

text 复制代码
NoUniqueBeanDefinitionException

因为 Spring 中会存在多个 DataSource Bean。


六、配置真实表

假设数据库已经存在:

text 复制代码
pay_info_202601
pay_info_202602
...
pay_info_203012

配置如下:

yaml 复制代码
spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          pay_info:
            actual-data-nodes:
              ds.pay_info_$->{202601..203012}

含义:

text 复制代码
逻辑表:
pay_info

真实表:
pay_info_202601
pay_info_202602
...
pay_info_203012

七、按月份分表

1. 配置分片策略

yaml 复制代码
table-strategy:
  standard:
    sharding-column: create_time
    sharding-algorithm-name: pay-info-month

2. sharding-column 是什么

表示:

text 复制代码
根据哪个字段决定路由

例如:

yaml 复制代码
sharding-column: create_time

表示:

text 复制代码
根据 create_time 决定数据进入哪张表

例如:

java 复制代码
2026-05-20

自动进入:

text 复制代码
pay_info_202605

3. 必须有 create_time 字段吗

不一定。

可以使用:

yaml 复制代码
sharding-column: pay_time

或者:

yaml 复制代码
sharding-column: order_time

只要能够表达时间即可。


八、配置时间分片算法

yaml 复制代码
sharding-algorithms:
  pay-info-month:
    type: INTERVAL
    props:
      datetime-pattern: yyyy-MM-dd HH:mm:ss
      datetime-lower: 2025-01-01 00:00:00
      datetime-upper: 2030-12-31 23:59:59
      sharding-suffix-pattern: yyyyMM
      datetime-interval-unit: MONTHS

1. datetime-pattern

时间格式。

yaml 复制代码
yyyy-MM-dd HH:mm:ss

例如:

java 复制代码
2026-05-18 15:20:30

2. datetime-lower

开始时间:

yaml 复制代码
2025-01-01 00:00:00

3. datetime-upper

结束时间:

yaml 复制代码
2030-12-31 23:59:59

4. sharding-suffix-pattern

表后缀格式。

例如:

yaml 复制代码
yyyyMM

生成:

text 复制代码
pay_info_202605

如果:

yaml 复制代码
yyyy_MM

生成:

text 复制代码
pay_info_2026_05

5. datetime-interval-unit

分片粒度。

按月:

yaml 复制代码
MONTHS

生成:

text 复制代码
pay_info_202605
pay_info_202606

按天:

yaml 复制代码
DAYS

生成:

text 复制代码
pay_info_20260501
pay_info_20260502

按年:

yaml 复制代码
YEARS

生成:

text 复制代码
pay_info_2025
pay_info_2026

九、MyBatis 和 MyBatis Plus 如何使用

1. Mapper 不需要修改

例如:

java 复制代码
@Mapper
public interface PayInfoMapper {

    PayInfo selectById(Long id);

}

2. XML 不需要修改

仍然写:

xml 复制代码
<select id="selectById">
    select *
    from pay_info
    where id = #{id}
</select>

不要写:

sql 复制代码
pay_info_202605

也不要写:

sql 复制代码
pay_info_202606

统一写:

sql 复制代码
pay_info

即可。


3. ShardingSphere 自动改写 SQL

程序:

sql 复制代码
select *
from pay_info

实际执行:

sql 复制代码
select *
from pay_info_202605

或者:

sql 复制代码
select *
from pay_info_202605
union all
select *
from pay_info_202606

十、查询如何路由

1. 精准路由

例如:

sql 复制代码
select *
from pay_info
where create_time >= '2026-05-01'
and create_time < '2026-06-01'

只查询:

text 复制代码
pay_info_202605

性能最好。


2. 范围路由

例如:

sql 复制代码
select *
from pay_info
where create_time between
'2026-05-01'
and
'2026-07-31'

查询:

text 复制代码
pay_info_202605
pay_info_202606
pay_info_202607

3. 全路由

例如:

sql 复制代码
select *
from pay_info
where status = 1

没有分片键:

sql 复制代码
create_time

ShardingSphere 无法判断目标表。

于是:

text 复制代码
pay_info_202601
pay_info_202602
...
pay_info_203012

全部查询。

这就是:

text 复制代码
全路由

性能极差。


十一、每个 SQL 都必须带分片键吗

不是必须。

可以正常执行。

但是:

text 复制代码
不带分片键
=
全路由
=
查询所有分表

因此在设计表结构时:

text 复制代码
高频查询条件
最好就是分片键

这样性能最高。


十二、ShardingSphere 会自动创建表吗

不会。

ShardingSphere 负责:

text 复制代码
SQL路由

不负责:

text 复制代码
创建表

例如:

sql 复制代码
insert into pay_info

路由到:

sql 复制代码
pay_info_202606

如果:

text 复制代码
pay_info_202606

不存在。

直接报错:

text 复制代码
Table doesn't exist

十三、如何自动创建分表

1. 推荐方案

提前创建未来几年表。

例如:

text 复制代码
pay_info_202601
...
pay_info_203012

一次建好即可。


2. 定时任务创建

假设每月1号创建未来三个月的表

(1)定时任务

java 复制代码
//每个月的 1 号凌晨 2 点整执行一次
@Scheduled(cron = "0 0 2 1 * ?")
public void createFutureTables() {
	//循环三次创建未来三个月的表
    for (int i = 1; i <= 3; i++) {
        LocalDate month = LocalDate.now().plusMonths(i);
		//检查表是否存在,不存在则创建
        createTableIfNotExists(month);
    }

}

(2)模板表

一般会准备一个模板表:

sql 复制代码
CREATE TABLE pay_info_template (
    id BIGINT PRIMARY KEY,
    order_no VARCHAR(64),
    amount DECIMAL(18,2),
    create_time DATETIME,
    KEY idx_create_time(create_time)
);

(3) 使用 JdbcTemplate 创建表

java 复制代码
@Autowired
private JdbcTemplate jdbcTemplate;

private void createTableIfNotExists(LocalDate month) {

    String tableName = String.format(
            "pay_info_%d_%02d",
            month.getYear(),
            month.getMonthValue()
    );

    String sql =
            "CREATE TABLE IF NOT EXISTS "
                    + tableName
                    + " LIKE pay_info_template";

    jdbcTemplate.execute(sql);

}

效果:

假设 当前是 2026-05 ,定时任务会执行:

sql 复制代码
CREATE TABLE IF NOT EXISTS pay_info_202606 LIKE pay_info_template;
CREATE TABLE IF NOT EXISTS pay_info_202607 LIKE pay_info_template
CREATE TABLE IF NOT EXISTS pay_info_202608 LIKE pay_info_template

最终创建了:

text 复制代码
pay_info_2026_06
pay_info_2026_07
pay_info_2026_08

3. Flyway 或 Liquibase

使用数据库版本管理工具自动创建。


十四、生产环境如何设计分表

1. 单纯按月份分表

text 复制代码
pay_info_202605
pay_info_202606
pay_info_202607

适合:

text 复制代码
按时间查询较多

2. 按用户 Hash 分表

text 复制代码
pay_info_00
pay_info_01
...
pay_info_63

路由:

java 复制代码
userId % 64

适合:

text 复制代码
根据用户查询较多

3. 时间 + Hash

大型支付系统最常见。

例如:

text 复制代码
pay_info_202605_00
pay_info_202605_01
...
pay_info_202605_15

优势:

  • 控制单表大小
  • 查询效率高
  • 扩展能力强

十五、ShardingSphere 的优缺点

优点

  • 对业务代码侵入小
  • MyBatis 基本不用改
  • 自动路由
  • 自动聚合结果
  • 支持读写分离
  • 支持分布式事务
  • 支持分库分表

缺点

  • 配置复杂
  • SQL 不宜过于复杂
  • 跨分片查询成本高
  • 全路由性能差
  • 分页查询需要特别注意

十六、总结

ShardingSphere 本质上是一个数据库中间层。

对于开发人员来说:

text 复制代码
仍然操作逻辑表
pay_info

对于数据库来说:

text 复制代码
实际访问真实表
pay_info_202605
pay_info_202606

其核心思想只有一句话:

text 复制代码
开发只关心逻辑表,
ShardingSphere负责将SQL路由到正确的真实表。
相关推荐
人道领域1 小时前
【LeetCode刷题日记】538.把二叉搜索树转换为累加树
java·开发语言·后端·算法·leetcode
铁皮哥1 小时前
【后端开发】什么是守护线程,和普通线程有什么区别?
java·开发语言·数据库·人工智能·python·spring·intellij-idea
Lsk_Smion1 小时前
力扣实训 _ [33].搜索旋转排序数组 _ [92].翻转链表Ⅱ
java·数据结构·算法
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第86题】【Mysql篇】第16题:MySQL 中锁的种类与行锁实现原理?
java·开发语言·数据库·mysql·面试
不爱编程的小陈1 小时前
Go内存模型与GC机制:高性能编程的核心
开发语言·后端·golang
code2roc1 小时前
SpringBoot整合Milvus向量数据库
数据库·spring boot·milvus·向量化
苏渡苇1 小时前
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
spring boot·docker·微服务·容器·kubernetes·seata·springcloud
日月云棠1 小时前
12 Enum —— 枚举类型的底层实现
java·后端
工位植物人1 小时前
深入理解Java中的类、抽象类、接口与枚举类
后端