2328 字
约 7 分钟
1
Sharding-JDBC 分库分表入门
2026-09-07
Sharding-JDBC 分库分表入门
1. 一句话简介
Sharding-JDBC 是 Apache ShardingSphere(前身是当当网开源的 sharding-jdbc)提供的一个客户端形态的分库分表组件,它以 jar 包的方式嵌入应用,在 JDBC 层与应用数据源之间加了一层代理:应用把 SQL 发给这个代理数据源,ShardingSphere 解析 SQL 后,根据预先配置的分片键(如 user_id、order_id)自动完成"分库路由、分表路由、SQL 改写、结果归并",并透明地路由到底层的多个 MySQL 实例上。核心解决的是单库单表在数据量增大后出现的容量瓶颈与查询性能下降问题——当一张表数据达到千万以上,单实例 IO、索引深度、写入锁竞争都会成为明显瓶颈,此时通过"把数据水平切分到多个库、多张表"来降低单表数据量、摊薄读写压力。
以本 demo(demo-sharding-jdbc)为例:DataSourceShardingConfig 中配置了 2 个数据源(spring-boot-demo、spring-boot-demo-2)和 6 张物理表,分库用行表达式 ds${user_id % 2}(按用户 ID 取模拆分到 2 个库),分表用 t_order_$->{order_id % 3}(按订单 ID 取模拆分到 3 张表)。对应用层(MyBatis-Plus 的 OrderMapper)而言,始终只面对逻辑表 t_order,底层的分片对业务代码完全透明。
2. 什么时候使用
✅ 适用场景
- 单表数据量持续增大、已达千万级以上:单表超过千万会有明显的索引性能下降和写入瓶颈,分库分表是水平扩展数据的常规手段。
- 需要同时分摊读写压力与存储容量:把数据按分片键拆到多个库、多张表,降低单库负载、充分利用多实例的 IO 与计算能力(本 demo 即 2 库 × 3 表的水平扩展)。
- 有明确、稳定且高区分度的分片键:如
user_id、order_id。只要查询、更新、删除都能带上该分片键,Sharding-JDBC 就能精确路由到单个物理节点,避免全表(broadcast)扫描,性能收益最明显(本 demo 的更新 testUpdate 能精确落到ds0.t_order_2一条实际 SQL)。 - 希望以低侵入方式接入、快速起步:以 jar 包形式嵌入 Spring Boot,通过 Java Config(
ShardingRuleConfiguration+ShardingDataSourceFactory)即可完成配置,无需部署额外的代理服务。 - 已有 Java 技术栈、希望与 MyBatis/JPA/JdbcTemplate 等 JDBC 生态无缝集成:分片对 ORM 层透明,本 demo 就与 MyBatis-Plus 的
BaseMapper结合实现了对逻辑表的增删改查。
❌ 不适用 / 需谨慎
- 业务刚起步、数据量远未到瓶颈:分库分表必然引入分布式事务、跨节点分布式主键、扩容/数据迁移改分片规则等额外复杂度,过早分片是典型的过度设计。
- 缺少稳定分片键、大量查询是跨分片聚合:若常按非分片键(如按时间、按商家全局统计)查询,会退化成对全部分片广播 + 内存归并,性能反而下降(本 demo 的 testSelect 因只带
order_id不带user_id,就需在 2 个库中各查多张表再归并)。 - 强事务、强一致性的分布式业务:分库后单库本地事务无法覆盖跨库操作。本 demo 虽配置了
DataSourceTransactionManager,但 ShardingSphere 的分布式事务能力有限,复杂跨片事务更适合用 Seata/XA 等方案。 - 分片键会频繁改变 / 数据量增长不可预期:取模分片策略一旦选好,扩容分片数需要重新计算数据分布并迁移,极其痛苦。
- 只需要读写分离、不需要分片:仅做主从读写分离时 ShardingSphere 也可以做,但若只是读扩展,标准主从复制或开源中间件可能更简单直接。
- 对自定义复杂 SQL、子查询、跨库 JOIN 兼容性要求极高:分片对 SQL 语法有限制(不支持跨库 JOIN、某些 CASE/HAVING 等),需要人工规避。
3. 常见业务场景
- 订单/交易系统的大数据量水平切分:这是分库分表最典型的代表。订单表增长极快,且天然具备
user_id、order_id两个稳定的路由维度。按用户分库、按订单分表(本 demo 的user_id % 2+order_id % 3即此模式),所有按用户/订单维度的读写都能精确路由,是收益最直接的应用。 - 用户 / 会员体系扩容:用户表达到千万级后可按
user_id均匀拆分。用户的登录、资料查询、积分明细等操作都带 user_id,分库分表后单用户请求稳定落在单个分片,适合冷热数据分离、地域就近部署。 - 日志 / 明细流水归档:操作日志、埋点明细、流水账单等"只增删、按 ID 查"的数据,天然适合按主键或时间取模分片,既压缩单表体积,又能在不需要时有条件清空单张物理表。
- 消息 / 任务明细表:消息中心、任务状态表数据量大且按接收人 ID 维度访问,分片后能让每个用户的查询只落到对应分片,避免大表锁竞争。
- 历史账单 / 对账单高速写入与查询:支付对账、财务报表明细表写入压力大,按用户或账户分片可摊薄单库写压力,同时查询按账户维度精确路由,与老技术选型冷热分库相结合效果更佳。
说明:以上场景共同点是——都有稳定、高区分的分片键,且绝大多数读写都带该键。这正是分库分表能带来收益的前提(对照本 demo:带
user_id+order_id的更新精确路由,不带user_id的查询则需广播归并)。
4. 同类技术对比
| 维度 | Sharding-JDBC(ShardingSphere 客户端) | MyCat / DBLE(服务端代理) | 单库大表 + 索引/读写分离优化 | 云数据库分布式分片(如 TDSQL、PolarDB-X) |
|---|---|---|---|---|
| 形态 | 客户端 jar 包,嵌入应用 JDBC 层 | 独立部署的数据库代理服务 | 无需中间件,纯数据库方案 | 云厂商托管的分片中间件 |
| 性能 | 高,无网络中转,直接连后端 | 中,多一跳网络代理,有连接转发开销 | 高但受单实例物理上限 | 较高,有额外协议开销 |
| 侵入性/部署 | 低,改配置即可,无额外部署 | 中,需独立运维代理集群 | 无侵入 | 低,但有厂商绑定 |
| 功能 | 分库分表、读写分离、分布式主键(雪花) | 分库分表、读写分离、SQL 路由 | 仅优化,不支持分片 | 分库分表 + 自动扩容 + 运维托管 |
| 分布式主键 | 内置/Snowflake,需自定义避免倾斜 | 需主键生成方案 | 数据库自增 | 提供全局主键 |
| 分布式事务 | 支持有限,复杂跨片需配 Seata | 支持有限 | 单机事务 | 支持较好 |
| 运维成本 | 低(纯代码集成) | 高(代理集群自身要运维) | 低但要持续手动扩容 | 低(托管) |
| 学习成本 | 低,熟悉 JDBC/Spring 即可 | 中,需学代理特有 SQL/规则 | 低 | 中 |
| 适用规模 | 中小到中大规模,数据量可控增长 | 中大规模,尤其多后端统一入口 | 单表仍在可接受范围 | 大规模,弹性扩容诉求明确 |
选型建议
- 中小规模、Java 技术栈、想快速无额外部署地上分库分表 → 优先选 Sharding-JDBC(本 demo 选型):侵入性低、性能高、与 MyBatis/JPA 等无缝,适合业务还在可控增长期。
- 多套异构后端、需要统一 SQL 接入入口,且能接受额外部署一套代理 → 选 MyCat / DBLE:把路由逻辑抽到独立服务,前端应用更"薄",但要承担代理本身的运维和性能损耗。
- 数据量其实还没到瓶颈、只是读写略慢 → 先做索引优化 + 读写分离即可,不要过早分片;分片是最后手段,复杂度远高于常规优化。
- 超大业务量、扩容频繁、想要托管免运维 → 考虑云上分布式分片,把自动扩容、迁移、备份交给云厂商,代价是有厂商绑定和额外成本。
- 通用结论:能用索引、缓存、读写分离解决就不分片;分片后务必备好稳定分片键与(如 ShardingSphere)支持的 SQL 子集,并把分布式主键、分布式事务提前纳入设计,避免后续返工。
评论
0 条
还没有评论,先写一条吧。