先给结论:如果你的业务表已经过了“单表能扛”的阶段,又不想引入太重的中间件,那 SpringBoot 2.7.18 + ShardingSphere-JDBC 5.2.1 做按月分表,配合 PostgreSQL + Druid + MyBatis-Plus,是一套能直接落地的组合。这套方案我最近刚在一张日增几十万流水、单表数据量过亿的业务表上完整跑通,从 Maven 依赖到分片算法、从 Druid 连接池到 MyBatis-Plus 分页,中间踩了不少版本和配置的坑。这篇文章会把完整的选型逻辑、配置拆解、排错路径和生产化建议都写清楚,适合正在做订单、日志、交易流水、轨迹记录这类“天然带时间维度”分表需求的同学参考。
为什么强调“按月分表”而不是常见的“按年分表”?因为对大部分流水表来说,一年的数据量往往还是太大,而按天分表又会导致物理表数量过多、跨表查询的路由成本上升。按月分表是一个折中方案:单表数据量可控,冷热归档方便,按时间范围查询时最多路由到十几张表,性能也还在可接受范围内。下面直接进入正题。
1. 为什么是这几个版本:选型复盘与前置认知
1.1 什么样的表适合做按月分表
不是所有表都适合分表,更不是所有分表都应该按月来。我建议你先判断三个特征:
- 表有明确的时间列,而且绝大多数查询都会带上这个时间条件,比如订单的创建时间、流水的发生时间、日志的记录时间。
- 写入存在明显的“尾部热点”,也就是说最新的数据写入最频繁,历史数据基本只读。
- 单表数据量已经达到千万到亿级别,索引维护成本明显上升,插入性能出现抖动。
如果你的表符合这几个特征,按月分表就是一个比较合理的选择。反过来,如果业务查询基本都按用户 ID 维度走、时间条件只是偶尔过滤,那优先考虑按用户 ID 哈希分片,或者直接用分布式数据库,不要硬套时间分表。
1.2 版本组合为什么锁定在 2.7.18 和 5.2.1
先说 SpringBoot,2.7.18 是 SpringBoot 2.x 的最终维护版本,也是很多存量项目升级成本最低的终点。ShardingSphere-JDBC 6.x 已经全面转向 SpringBoot 3 / Jakarta EE,如果你的项目还停留在 JDK 8 和 javax 体系,SpringBoot 2.7.18 反而是最稳妥的长期版本。
再看 ShardingSphere-JDBC,5.2.1 是我在这个组合里实际验证过的版本。为什么不用更高版本?因为 5.3.x 之后对 SpringBoot 自动装配、YAML 配置结构的兼容性有过调整,有些配置项写法会变;而 5.1.x 在标准分片算法和范围查询上的表现又没有 5.2.x 完整。5.2.1 恰好处于一个“功能丰富度”和“配置稳定性”都比较平衡的位置。
依赖的 artifactId 也要注意,5.2.1 对应的 starter 已经改成了 shardingsphere-jdbc-core-spring-boot-starter,不是早期 4.x 时代的 sharding-jdbc-spring-boot-starter。如果你在搜索引擎里看到老文章,引用了旧包名,启动时会直接报一大堆自动配置类找不到的错误。
1.3 JDBC 模式和 Proxy 模式的取舍
ShardingSphere 有 JDBC 和 Proxy 两种形态,这里选 JDBC 是因为它直接嵌入在应用进程里,不需要额外部署一个 Proxy 节点,对中小团队来说运维成本最低。JDBC 模式本质上就是帮你包了一层 DataSource,应用拿到的还是一个标准数据源,MyBatis-Plus、Druid、事务管理器都感知不到分片逻辑,业务代码也不需要改动。
代价也很直接:分片逻辑在应用内存里计算,每个应用节点都要维护一份分片元数据;如果应用是多实例部署,连接数会被放大。所以 JDBC 模式更适合应用实例数量不多、单实例连接数可控的场景。如果你的服务有几十个 Pod,那建议认真评估 Proxy 模式或用分布式数据库,而不是硬上 JDBC。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 第一步先把数据和依赖铺好
2.1 PostgreSQL 中物理表的创建与命名规范
分表之前,物理表要先存在。ShardingSphere 只负责把逻辑表的路由改写为物理表,没有自动建表能力。我习惯的命名方式是 逻辑表名_yyyyMM,比如交易流水表逻辑名为 t_trade_flow,物理表就是 t_trade_flow_202501、t_trade_flow_202502。
PostgreSQL 表名和字段名默认会被折叠成小写,这本身不是问题,但如果你在建表脚本里给表名加了双引号,比如 CREATE TABLE "T_TRADE_FLOW_202501",那这个表名就会以大写形式存储。ShardingSphere 在做路由匹配时用的是小写逻辑名,两边的表名对不上,就会出现“明明表存在却报 relation not exist”的诡异问题。所以建议表名全部使用小写,不要给表名加双引号。
建表时还要特别注意分区表的冲突问题。PostgreSQL 原生支持 PARTITION BY RANGE,如果你已经用原生分区表,那就不需要 ShardingSphere 再来做分表;反过来也是一样,别把两层机制叠在一起,否则查询计划会变得非常不可控。我这里使用的是普通物理表,不用 PostgreSQL 原生分区,分片完全交给 ShardingSphere 处理。
2.2 pom.xml 依赖和版本排除细节
依赖这块最容易出问题,因为 ShardingSphere 会传递一堆依赖,和 SpringBoot 自带的版本管理打架。核心依赖如下:
xml复制<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
需要注意 ShardingSphere 5.2.1 自带的 SnakeYAML 版本可能偏低,在某些环境下会报安全漏洞扫描不通过。处理方式不是盲目升级 SnakeYAML 版本,而是确认 SpringBoot 2.7.18 自带的依赖版本能够统一覆盖它。不建议自行排除后再引高版本,因为 Sha
