ShardingSphere-JDBC 入门教程之四
大纲
- ShardingSphere-JDBC 入门教程之一、ShardingSphere-JDBC 入门教程之二、ShardingSphere-JDBC 入门教程之三
- ShardingSphere-JDBC 入门教程之四、ShardingSphere-JDBC 入门教程之五、ShardingSphere-JDBC 入门教程之六
- ShardingSphere-JDBC 入门教程之七、ShardingSphere-JDBC 入门教程之八、ShardingSphere-JDBC 入门教程之九
前言
学习资源
- ShardingSphere 官方项目(GitHub)
- ShardingSphere 官方网站(中文站点)
- ShardingSphere 官方文档(最新版本)
- ShardingSphere 官方文档(5.1.1 版本)
ShardingSphere-JDBC 分布式序列算法
水平分片(包括水平分库和水平分表)需要关注分布式序列(即分布式全局唯一 ID),因为不能简单的使用基于数据库的自增主键,否则不同库不同表之间会发生主键冲突。通常主键冲突有两种解决方案:一种是使用 MyBatis-Plus 的 ID 生成策略;一种是使用 ShardingSphere-JDBC 的分布式序列配置。
MyBatis-Plus 的 ID 生成策略
- 使用 MyBatis-Plus 的 ID 生成策略
ASSIGN_ID(默认是基于 Snowflake 算法实现)
1 |
|
- 在 MyBatis-Plus 中,Snowflake 算法生成的 ID 是一个 64 位长整型(
| 1 bit 符号位 | 41 bit 时间戳 | 5 bit 数据中心 ID | 5 bit 工作机器 ID | 12 bit 序列号 |),其默认的 Snowflake 参数为:
| 参数 | 默认值 | 说明 | |
|---|---|---|---|
dataCenterId | 1 | 数据中心 ID(0 ~ 31) | |
workerId | 1 | 工作机器 ID(0 ~ 31) |
- 在 MyBatis-Plus 中,Snowflake 参数的默认值在分布式部署时可能会出现 ID 冲突,因此通常需要自定义 Snowflake 参数(包括
dataCenterId和workerId),避免 ID 冲突的发生
1 | import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; |
ShardingSphere 的分布式序列
ShardingSphere-JDBC 内置了两种分布式序列算法(即分布式 ID 生成算法),包括 SNOWFLAKE 和 UUID,可用于生成分布式全局唯一 ID。
SNOWFLAKE 算法
- 配置 ShardingSphere-JDBC 使用
SNOWFLAKE分布式序列算法
1 | # ----------分布式序列策略配置---------- |
- 此时,需要将实体类中的 MyBatis-Plus 的 ID 生成策略修改为
AUTO或者NONE:
1 |
|
- ShardingSphere-JDBC 的
SNOWFLAKE分布式序列算法支持配置以下属性:
| 属性名称 | 数据类型 | 说明 | 默认值 |
|---|---|---|---|
max-vibration-offset | int | 最大抖动上限值,范围是 [0, 4096)。注意:若使用此算法生成值作分片值(分片列的值),建议配置此属性。此算法在不同毫秒内所生成的 Key 取模 2^n(这里的 2^n 一般为分库或分表数量)之后结果总为 0 或 1。该属性的作用是为了让同一毫秒生成的 ID,最终的分片取模结果不总是落在同一个库 / 表上,用于避免分片倾斜(热点分片)问题。 为防止上述分片问题,建议将此属性值配置为 (2^n) - 1。 | 1 |
max-tolerate-time-difference-milliseconds | long | 最大容忍时钟回退时间,单位:毫秒 | 10 |
SNOWFLAKE分布式序列算法中,max-vibration-offset属性的配置示例:
| 分库数量 | 2^n | max-vibration-offset 的建议值 (2^n) - 1 |
|---|---|---|
| 2 库 | 2¹=2 | 1 |
| 4 库 | 2²=4 | 3 |
| 8 库 | 2³=8 | 7 |
| 16 库 | 2⁴=16 | 15 |
| 32 库 | 2⁵=32 | 31 |
总结
在 ShardingSphere-JDBC 的 SNOWFLAKE 分布式序列算法中,max-vibration-offset 属性用来给 Snowflake ID 在同一毫秒内增加随机性,避免分片时总落到某几个库 / 表,防止热点库 / 表的出现。
UUID 算法
- 配置 ShardingSphere-JDBC 使用
UUID分布式序列算法
1 | # ----------分布式序列策略配置---------- |
- 此时,需要将实体类中的 MyBatis-Plus 的 ID 生成策略修改为
NONE:
1 |
|
ShardingSphere-JDBC 分片算法
分片算法的类型
ShardingSphere-JDBC 内置的分片算法如下所示:
自动分片算法
- 取模分片算法(
MOD)- 概述:对分片键取模,决定路由的库 / 表序号。
- 特点:算法简单、性能高、均匀分布。
- 适用场景:用户 ID、订单 ID 等数值型字段且写请求均匀分布的场景。
- 哈希取模分片算法(
HASH_MOD)- 概述:对分片键先做哈希,再取模。
- 特点:分布更均匀,避免 ID 递增导致热点。
- 适用场景:字符串类型分片键(如手机号、Email、UUID)。
- 基于分片容量的范围分片算法(
VOLUME_RANGE)- 概述:按单分片最大承载容量进行范围分片。
- 特点:按数据量增长自动落到不同库 / 表。
- 适用场景:数据量随时间增长、按容量控制每个分片大小(如日志类业务)。
- 基于分片边界的范围分片算法(
BOUNDARY_RANGE)- 概述:在配置中预先定义各分片的边界范围。
- 特点:控制精确,可与业务范围区间对应。
- 适用场景:省份编码、分等级、金额区间等明确范围的业务。
- 自动时间段分片算法(
AUTO_INTERVAL)- 概述:按时间自动生成分片,比如每天 / 每月自动建表。
- 特点:避免手动扩容,时间分片自动推进。
- 适用场景:日志表、订单表、流水表的按时间分表。
- 取模分片算法(
标准分片算法
- 行表达式分片算法(
INLINE)- 概述:使用 Groovy 表达式生成路由,如
t_order_$->{user_id % 4}。 - 特点:灵活、配置简单、可自定义表达式。
- 适用场景:分片条件规则清晰,可用简单表达式定义的场景。
- 概述:使用 Groovy 表达式生成路由,如
- 时间范围分片算法(
INTERVAL)- 概述:通过时间区间计算应该路由到哪个时间分片。
- 特点:支持 “时间 → 表名” 的表达式映射。
- 适用场景:按年 / 月 / 天的时间序列数据分表(如日志、订单流水)。
- 行表达式分片算法(
复合分片算法
- 复合行表达式分片算法(
COMPLEX_INLINE)- 概述:支持多个分片键,通过表达式组合路由。
- 特点:多维条件路由,灵活性高。
- 适用场景:订单场景:需按
user_id、order_time等联合多个键决定路由。
- 复合行表达式分片算法(
Hint 分片算法
- Hint 行表达式分片算法(
HINT_INLINE)- 概述:基于 Hint(SQL 注入式强制路由值)的表达式算法。
- 特点:程序员通过代码显式指定分片,不依赖 SQL 条件。
- 适用场景:
- SQL 本身没有分片字段(例如跨库 JOIN 时强制路由)
- 使用中间件或服务层统一指定分片键
- 灰度 / 运营类特殊请求
- Hint 行表达式分片算法(
自定义类分片算法
ShardingSphere-JDBC 除了提供内置的分片算法,还支持开发者自定义类分片算法(CLASS_BASED),可通过配置分片策略类型和算法类名,实现自定义扩展。
分片算法的使用
特别注意
ShardingSphere-JDBC 内置的分片算法同时适用于垂直分片(垂直分库、垂直分表)和水平分片(水平分库、水平分表)。由于篇幅限制,下面仅展示部分分片算法的配置示例。
水平分库
这里以水平分库为例子,演示如何使用 ShardingSphere-JDBC 提供的分片算法进行分库。
分库规则:
t_order逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server-order0);user_id为奇数时,数据插入到订单数据库服务器二(server-order1)。- 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
- 值得一提的,由于这里每个库只有一张表,所以只需要配置分库策略(
database-strategy),所以不需要配置分表策略(table-strategy)。
数据结构:
1
2
3
4server-order0
└── t_order
server-order1
└── t_order
行表达式分片算法
1 | # ----------数据源配置---------- |
取模分片算法
1 | # ----------数据源配置---------- |
哈希取模分片算法
1 | # ----------数据源配置---------- |
水平分表
这里以水平分表为例子,演示如何使用 ShardingSphere-JDBC 提供的分片算法进行分表。由于篇幅有限,这里仅介绍哈希取模分片算法的使用,其他分片算法可以参考上面 水平分库 的使用。
分表规则:
t_order逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order1表。- 值得一提的是,由于这里只有一个数据库(即单库分表),所以只需要配置分表策略(
table-strategy),不需要配置分库策略(database-strategy)。 - 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
数据结构:
1
2
3server-order0
├── t_order0
└── t_order1
哈希取模分片算法
1 | # ----------数据源配置---------- |
水平分库与水平分表
这里以水平分库 + 水平分表为例子,演示如何使用 ShardingSphere-JDBC 提供的分片算法。
分库规则:
t_order逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server-order0);user_id为奇数时,数据插入到订单数据库服务器二(server-order1)。- 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
分表规则:
t_order逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
数据结构:
1
2
3
4
5
6server-order0
├── t_order0
└── t_order1
server-order1
├── t_order0
└── t_order1
1 | # ----------数据源配置---------- |
ShardingSphere-JDBC 使用
水平分库使用案例
提示
本节将演示 SpringBoot + MyBatis-Plus 如何整合 ShardingSphere-JDBC,并实现 水平分库,即根据某个字段(或几个字段)通过特定规则,将数据分散到多个库或表中,每个分片只存储部分数据。例如,可按主键分片:偶数主键记录放入 0 库(或表),奇数主键记录放入 1 库(或表),如图所示。水平分库通常是在水平分表的基础上进一步进行,将原本分散到多张表的数据继续分布到多台数据库服务器上,以提升整体的并发处理能力。完整的案例代码可以直接从 GitHub 下载对应章节 shardingsphere-jdbc-lesson-03。
准备工作
版本说明
本案例所使用的组件版本如下表所示:
| 组件 | 版本说明 |
|---|---|
| JDK | 11 |
| MySQL | 8.0.29 |
| SpringBoot | 2.7.18 |
| MyBatis-Plus | 3.3.1 |
| ShardingSphere-JDBC | 5.1.1 |
数据库规划
本案例是在两个 MySQL 数据库上实现的,数据库的规划如下图所示:

| 数据库服务器 | IP | 端口 | 库的名称 | 表的名称 |
|---|---|---|---|---|
订单数据库服务器一(server-order0) | 192.168.2.191 | 3310 | db_order | t_order0、t_order1 |
订单数据库服务器二(server-order1) | 192.168.2.191 | 3311 | db_order | t_order0、t_order1 |
数据库部署
- 部署订单数据库服务器一(
server-order0)
1 | # 创建并启动 MySQL 容器(Docker 会自动在宿主机上创建不存在的目录) |
- 更改订单数据库服务器一(
server-order0)的默认密码校验方式
1 | # 进入容器内,其中环境变量 "env LANG=C.UTF-8" 用于避免容器内显示中文乱码的问题 |
- 部署订单数据库服务器二(
server-order1)
1 | # 创建并启动 MySQL 容器(Docker 会自动在宿主机上创建不存在的目录) |
- 更改订单数据库服务器二(
server-order1)的默认密码校验方式
1 | # 进入容器内,其中环境变量 "env LANG=C.UTF-8" 用于避免容器内显示中文乱码的问题 |
数据库初始化
- 在订单数据库服务器一(
server-order0)中,执行以下 SQL 语句:
1 | -- 创建数据库 |
- 在订单数据库服务器二(
server-order1)中,执行以下 SQL 语句:
1 | -- 创建数据库 |
案例代码
添加依赖
1 | <properties> |
创建实体类
- 订单实体类(特别注意:分库分表场景下不能使用数据库的自增主键,必须采用分布式全局唯一 ID,否则不同库不同表之间会发生主键冲突)
1 | import com.baomidou.mybatisplus.annotation.IdType; |
创建 Mapper
- 订单 Mapper
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
配置数据分片
这里的配置以水平分库为例子,演示如何使用 ShardingSphere-JDBC 提供的分片算法,其中分片规则如下:
分库规则:
t_order逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server-order0);user_id为奇数时,数据插入到订单数据库服务器二(server-order1)。- 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
分表规则:
t_order逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
数据库规划:

- 创建配置文件(
application.properties),配置数据分片
1 | # ----------基础配置---------- |
- 为了简化标准分片表的配置,ShardingSphere JDBC 提供了行表达式,其使用教程可以看 这里。使用行表达式后,上面的标准分片表配置(数据节点)可以改写为以下形式:
1 | # 标准分片表配置(数据节点) |
官方文档
测试代码
插入数据
1 |
|
测试代码运行后的输出结果如下:
1 | 2022-09-08 20:34:21.671 INFO 8730 --- [main] ShardingSphere-SQL : Logic SQL: INSERT INTO t_order (order_no, user_id, amount) VALUES (?, ?, ?) |
查询所有数据
1 |
|
测试代码运行后的输出结果如下:
1 | 2022-09-08 20:50:58.805 INFO 34995 --- [ main] ShardingSphere-SQL : Logic SQL: SELECT id,order_no,user_id,amount FROM t_order |
根据条件查询数据
1 |
|
测试代码运行后的输出结果如下:
1 | 2022-09-08 20:53:56.433 INFO 35828 --- [main] ShardingSphere-SQL : Logic SQL: SELECT id,order_no,user_id,amount FROM t_order WHERE (user_id = ?) |
