目录
- 前言
- 一、为什么需要 ShardingSphere
- 二、什么是 ShardingSphere
- 三、ShardingSphere 解决了什么问题
- 四、ShardingSphere 的核心概念
- 1. 逻辑表
- 2. 真实表
- 3. 分片键
- 4. 分片算法
- 五、Spring Boot 集成 ShardingSphere
- 1. 引入依赖
- 2. 配置数据源
- 3. 是否还需要 spring.datasource
- 六、配置真实表
- 七、按月份分表
- 1. 配置分片策略
- 2. sharding-column 是什么
- 3. 必须有 create_time 字段吗
- 八、配置时间分片算法
- 1. datetime-pattern
- 2. datetime-lower
- 3. datetime-upper
- 4. sharding-suffix-pattern
- 5. datetime-interval-unit
- 九、MyBatis 和 MyBatis Plus 如何使用
- 1. Mapper 不需要修改
- 2. XML 不需要修改
- 3. ShardingSphere 自动改写 SQL
- 十、查询如何路由
- 1. 精准路由
- 2. 范围路由
- 3. 全路由
- 十一、每个 SQL 都必须带分片键吗
- 十二、ShardingSphere 会自动创建表吗
- 十三、如何自动创建分表
- 1. 推荐方案
- 2. 定时任务创建
- 3. Flyway 或 Liquibase
- 十四、生产环境如何设计分表
- 1. 单纯按月份分表
- 2. 按用户 Hash 分表
- 3. 时间 + Hash
- 十五、ShardingSphere 的优缺点
- 优点
- 缺点
- 十六、总结
前言
随着业务的发展,订单表、支付表、交易流水表等核心业务表的数据量会不断增长。当单表数据达到数千万甚至上亿级别时,查询性能、索引维护、数据备份和数据库扩容等问题都会逐渐显现。
为了解决单表数据量过大的问题,互联网系统通常会采用分库分表方案,将数据按照一定规则拆分到多个数据库或数据表中。然而,分库分表之后也会带来新的挑战,例如如何确定数据应该存储到哪张表、如何跨表查询数据、如何降低业务代码的改造成本等。
ShardingSphere正是为了解决这些问题而诞生的。它能够在应用层和数据库之间提供透明的分片能力,让开发人员仍然像操作普通数据表一样进行开发,而无需关心底层的数据路由和 SQL 改写过程。
本文将结合 Spring Boot 和 MyBatis 项目,从分库分表的背景开始,逐步介绍 ShardingSphere 的核心概念、工作原理、项目集成方式、分片算法配置以及实际项目中的使用技巧,帮助读者快速掌握 ShardingSphere 的基本使用与设计思路。
shardingsphere官网
shardingsphere HitHub地址
一、为什么需要 ShardingSphere
随着业务发展,订单表、支付表、流水表的数据量会越来越大。
例如有一张支付订单表:
CREATETABLEpay_info(idBIGINTPRIMARYKEY,order_noVARCHAR(64),user_idBIGINT,amountDECIMAL(18,2),create_timeDATETIME);如果每天产生 100 万条数据:
100万/天 ≈ 3000万/月 ≈ 3.6亿/年几年之后,单表可能达到几十亿数据。
此时会出现很多问题:
- 查询变慢
- 索引变大
- 备份恢复困难
- DDL操作耗时
- 数据迁移困难
因此需要进行:
分库分表最常见的方案:
- 按时间分表
- 按用户分表
- 按订单号分表
而目前 Java 生态中最主流的分库分表框架之一就是 Apache ShardingSphere。
二、什么是 ShardingSphere
ShardingSphere 是 Apache 顶级项目。
它是一套数据库中间件生态,主要功能包括:
- 分库分表
- 读写分离
- 分布式事务
- 数据加密
- SQL 路由
- SQL 改写
在 Spring Boot 项目中最常见的是:
ShardingSphere-JDBC其架构如下:
MyBatis ↓ ShardingSphere ↓ MySQL对于业务代码来说:
感知不到分表的存在三、ShardingSphere 解决了什么问题
假设数据库中有以下表:
pay_info_202601 pay_info_202602 pay_info_202603 ...程序中仍然写:
select*frompay_info或者:
payInfoMapper.insert(payInfo);增删改查时 ShardingSphere 会自动帮你改写 SQL。
例如:
createTime=2026-05-15自动路由:
insertintopay_info_202605开发人员完全不需要手动判断表名。
四、ShardingSphere 的核心概念
1. 逻辑表
程序中看到的表:
pay_info称为逻辑表。
例如:
select*frompay_info2. 真实表
数据库真正存在的表:
pay_info_202601 pay_info_202602 pay_info_202603称为真实表。
3. 分片键
决定数据进入哪张表的字段。
例如:
create_time或者:
user_id或者:
order_no都可以作为分片键。
4. 分片算法
根据分片键计算目标表。
例如:
2026-05-15计算得到:
pay_info_202605五、Spring Boot 集成 ShardingSphere
1. 引入依赖
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId></dependency>2. 配置数据源
spring:shardingsphere:datasource:names:dsds:type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/testusername:rootpassword:root这里的:
url username password就是实际数据库连接配置。
3. 是否还需要 spring.datasource
上面在 shardingsphere 下已经配置了数据源了,是否还需要 spring.datasource ?
通常不需要。
不要同时配置:
spring:datasource:和:
spring:shardingsphere:datasource:否则可能出现:
NoUniqueBeanDefinitionException因为 Spring 中会存在多个 DataSource Bean。
六、配置真实表
假设数据库已经存在:
pay_info_202601 pay_info_202602 ... pay_info_203012配置如下:
spring:shardingsphere:rules:sharding:tables:pay_info:actual-data-nodes:ds.pay_info_$->{202601..203012}含义:
逻辑表: pay_info 真实表: pay_info_202601 pay_info_202602 ... pay_info_203012七、按月份分表
1. 配置分片策略
table-strategy:standard:sharding-column:create_timesharding-algorithm-name:pay-info-month2. sharding-column 是什么
表示:
根据哪个字段决定路由例如:
sharding-column:create_time表示:
根据 create_time 决定数据进入哪张表例如:
2026-05-20自动进入:
pay_info_2026053. 必须有 create_time 字段吗
不一定。
可以使用:
sharding-column:pay_time或者:
sharding-column:order_time只要能够表达时间即可。
八、配置时间分片算法
sharding-algorithms:pay-info-month:type:INTERVALprops:datetime-pattern:yyyy-MM-dd HH:mm:ssdatetime-lower:2025-01-01 00:00:00datetime-upper:2030-12-31 23:59:59sharding-suffix-pattern:yyyyMMdatetime-interval-unit:MONTHS1. datetime-pattern
时间格式。
yyyy-MM-dd HH:mm:ss例如:
2026-05-1815:20:302. datetime-lower
开始时间:
2025-01-01 00:00:003. datetime-upper
结束时间:
2030-12-31 23:59:594. sharding-suffix-pattern
表后缀格式。
例如:
yyyyMM生成:
pay_info_202605如果:
yyyy_MM生成:
pay_info_2026_055. datetime-interval-unit
分片粒度。
按月:
MONTHS生成:
pay_info_202605 pay_info_202606按天:
DAYS生成:
pay_info_20260501 pay_info_20260502按年:
YEARS生成:
pay_info_2025 pay_info_2026九、MyBatis 和 MyBatis Plus 如何使用
1. Mapper 不需要修改
例如:
@MapperpublicinterfacePayInfoMapper{PayInfoselectById(Longid);}2. XML 不需要修改
仍然写:
<selectid="selectById">select * from pay_info where id = #{id}</select>不要写:
pay_info_202605也不要写:
pay_info_202606统一写:
pay_info即可。
3. ShardingSphere 自动改写 SQL
程序:
select*frompay_info实际执行:
select*frompay_info_202605或者:
select*frompay_info_202605unionallselect*frompay_info_202606十、查询如何路由
1. 精准路由
例如:
select*frompay_infowherecreate_time>='2026-05-01'andcreate_time<'2026-06-01'只查询:
pay_info_202605性能最好。
2. 范围路由
例如:
select*frompay_infowherecreate_timebetween'2026-05-01'and'2026-07-31'查询:
pay_info_202605 pay_info_202606 pay_info_2026073. 全路由
例如:
select*frompay_infowherestatus=1没有分片键:
create_timeShardingSphere 无法判断目标表。
于是:
pay_info_202601 pay_info_202602 ... pay_info_203012全部查询。
这就是:
全路由性能极差。
十一、每个 SQL 都必须带分片键吗
不是必须。
可以正常执行。
但是:
不带分片键 = 全路由 = 查询所有分表因此在设计表结构时:
高频查询条件 最好就是分片键这样性能最高。
十二、ShardingSphere 会自动创建表吗
不会。
ShardingSphere 负责:
SQL路由不负责:
创建表例如:
insertintopay_info路由到:
pay_info_202606如果:
pay_info_202606不存在。
直接报错:
Table doesn't exist十三、如何自动创建分表
1. 推荐方案
提前创建未来几年表。
例如:
pay_info_202601 ... pay_info_203012一次建好即可。
2. 定时任务创建
假设每月1号创建未来三个月的表
(1)定时任务
//每个月的 1 号凌晨 2 点整执行一次@Scheduled(cron="0 0 2 1 * ?")publicvoidcreateFutureTables(){//循环三次创建未来三个月的表for(inti=1;i<=3;i++){LocalDatemonth=LocalDate.now().plusMonths(i);//检查表是否存在,不存在则创建createTableIfNotExists(month);}}(2)模板表
一般会准备一个模板表:
CREATETABLEpay_info_template(idBIGINTPRIMARYKEY,order_noVARCHAR(64),amountDECIMAL(18,2),create_timeDATETIME,KEYidx_create_time(create_time));(3) 使用 JdbcTemplate 创建表
@AutowiredprivateJdbcTemplatejdbcTemplate;privatevoidcreateTableIfNotExists(LocalDatemonth){StringtableName=String.format("pay_info_%d_%02d",month.getYear(),month.getMonthValue());Stringsql="CREATE TABLE IF NOT EXISTS "+tableName+" LIKE pay_info_template";jdbcTemplate.execute(sql);}效果:
假设 当前是2026-05,定时任务会执行:
CREATETABLEIFNOTEXISTSpay_info_202606LIKEpay_info_template;CREATETABLEIFNOTEXISTSpay_info_202607LIKEpay_info_templateCREATETABLEIFNOTEXISTSpay_info_202608LIKEpay_info_template最终创建了:
pay_info_2026_06 pay_info_2026_07 pay_info_2026_083. Flyway 或 Liquibase
使用数据库版本管理工具自动创建。
十四、生产环境如何设计分表
1. 单纯按月份分表
pay_info_202605 pay_info_202606 pay_info_202607适合:
按时间查询较多2. 按用户 Hash 分表
pay_info_00 pay_info_01 ... pay_info_63路由:
userId%64适合:
根据用户查询较多3. 时间 + Hash
大型支付系统最常见。
例如:
pay_info_202605_00 pay_info_202605_01 ... pay_info_202605_15优势:
- 控制单表大小
- 查询效率高
- 扩展能力强
十五、ShardingSphere 的优缺点
优点
- 对业务代码侵入小
- MyBatis 基本不用改
- 自动路由
- 自动聚合结果
- 支持读写分离
- 支持分布式事务
- 支持分库分表
缺点
- 配置复杂
- SQL 不宜过于复杂
- 跨分片查询成本高
- 全路由性能差
- 分页查询需要特别注意
十六、总结
ShardingSphere 本质上是一个数据库中间层。
对于开发人员来说:
仍然操作逻辑表 pay_info对于数据库来说:
实际访问真实表 pay_info_202605 pay_info_202606其核心思想只有一句话:
开发只关心逻辑表, ShardingSphere负责将SQL路由到正确的真实表。