ShardingSphere-Proxy 入门教程之五
大纲
- ShardingSphere-Proxy 入门教程之一、ShardingSphere-Proxy 入门教程之二、ShardingSphere-Proxy 入门教程之三
- ShardingSphere-Proxy 入门教程之四、ShardingSphere-Proxy 入门教程之五、ShardingSphere-Proxy 入门教程之六
- ShardingSphere-Proxy 入门教程之七
前言
学习资源
- ShardingSphere 官方项目(GitHub)
- ShardingSphere 官方网站(中文站点)
- ShardingSphere 官方文档(最新版本)
- ShardingSphere 官方文档(5.1.1 版本)
ShardingSphere-Proxy 使用
水平分库使用案例
准备工作
版本说明
本节所有案例使用的组件版本如下表所示:
| 组件 | 版本说明 |
|---|---|
| JDK | 11 |
| MySQL | 8.0.29 |
| SpringBoot | 2.7.18 |
| MyBatis-Plus | 3.3.1 |
| ShardingSphere-Proxy | 5.1.1 |
数据库规划
本节所有案例是在两个 MySQL 数据库上实现的,数据库的规划如下图所示:

| 数据库服务器 | IP | 端口 | 库的名称 | 表的名称 |
|---|---|---|---|---|
订单数据库服务器一(server_order0) | 192.168.2.191 | 3310 | db_order | t_order0、t_order1、t_order_item0、t_order_item1 |
订单数据库服务器二(server_order1) | 192.168.2.191 | 3311 | db_order | t_order0、t_order1、t_order_item0、t_order_item1 |
| ShardingSphere-Proxy 服务器 | 192.168.2.191 | 3309 | sharding_db(逻辑库) | t_order(逻辑表)、t_order_item(逻辑表) |
数据库部署
- 部署订单数据库服务器一(
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 | -- 创建数据库 |
多表关联使用案例
提示
本节将演示 SpringBoot + MyBatis-Plus 如何通过 ShardingSphere-Proxy 在 水平分库 的基础上实现多表关联数据插入。水平分库会根据某个字段(或几个字段)通过特定规则,将数据分散到多个库或表中,每个分片只存储部分数据。例如,可按主键分片:偶数主键记录放入 0 库(或表),奇数主键记录放入 1 库(或表),如图所示。水平分库通常是在水平分表的基础上进一步进行,将原本分散到多张表的数据继续分布到多台数据库服务器上,以提升整体的并发处理能力。完整的案例代码可以直接从 GitHub 下载对应章节 shardingsphere-proxy-lesson-04。
核心概念介绍
多表关联(JOIN)能力并非 ShardingSphere-Proxy 额外提供的数据库功能,而是基于数据库本身的设计与约束。ShardingSphere-Proxy 只是对符合其分片规则与绑定表规则的 JOIN SQL 进行解析、路由与结果归并;是否能够高效甚至正确地执行多表关联,核心取决于表结构设计、分片键选择以及是否配置了绑定表,而非 ShardingSphere-Proxy 本身创造了新的关联能力。
ShardingSphere-Proxy 配置
这里的配置以水平分库为例子,演示如何使用 ShardingSphere-Proxy 提供的分片算法(包括 YAML 和 DistSQL 两种配置方式),其中分片规则如下:
分库规则:
- 订单表(
t_order):t_order逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server_order0);user_id为奇数时,数据插入到订单数据库服务器二(server_order1)。- 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
- 订单详情表(
t_order_item):t_order_item逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server_order0);user_id为奇数时,数据插入到订单数据库服务器二(server_order1)。- 这样分库的好处是,同一个用户的订单详情数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单详情时效率较高。
- 订单表(
分表规则:
- 订单表(
t_order):t_order逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
- 订单详情表(
t_order_item):t_order_item逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order_item0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order_item1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
- 订单表(
数据库规划:

特别注意
这里希望同一个用户的订单表和订单详情表中的数据都在同一个数据源中,避免跨库关联,因此订单表和订单详情表使用相同的分库规则。无论 ShardingSphere-Proxy 是使用 YAML 配置 还是 DistSQL 配置,都必须注意 ShardingSphere-Proxy 的版本差异。不同版本之间支持的 DistSQL 命令、YAML 配置语法以及参数格式可能存在较大差异,同一份配置在不同版本下可能无法直接执行或行为不一致,因此在编写和迁移配置时必须结合 ShardingSphere-Proxy 具体版本进行验证。
YAML 配置
- 创建或编辑 ShardingSphere-Proxy 的
conf/config-sharding.yaml配置文件,添加以下水平分库的配置内容:
1 | # 逻辑数据库(Schema)的名称 |
- ShardingSphere-Proxy 水平分库的配置内容添加完成后,需要重启 ShardingSphere-Proxy 服务(假设这里是通过 Docker 部署 ShardingSphere-Proxy 服务),否则配置不会生效
1 | # 重启 Docker 容器 |
- 验证 ShardingSphere-Proxy 中的配置规则是否生效(ShardingSphere-Proxy 启动时会从 YAML 配置文件中加载规则)
1 | # 远程连接 ShardingSphere-Proxy |
1 | -- 查询所有数据库 |
DistSQL 配置
- 创建逻辑数据库(Schema)
1 | -- 创建逻辑数据库(Schema) |
- 添加数据源
1 | -- 添加第一个数据源 |
1 | -- 添加第二个数据源 |
- 创建分片算法
1 | -- 创建取模算法 |
1 | -- 创建哈希取模算法 |
- 创建分布式序列算法
1 | -- 创建 Snowflake 雪花算法 |
- 创建分片规则
1 | -- 创建订单表的分片规则 |
1 | -- 创建订单详情表的分片规则 |
- 验证配置规则是否生效(使用 DistSQL 定义数据源和数据分片规则后,不需要重启 ShardingSphere-Proxy 服务,默认会自动生效)
1 | -- 查询所有数据库 |
查看日志信息
- 查看 ShardingSphere-Proxy 运行的实时日志信息
1 | # 进入容器内,其中环境变量 "env LANG=C.UTF-8" 用于避免容器内显示中文乱码的问题 |
特别注意
在开发或者测试环境中,若希望 ShardingSphere-Proxy 输出详细的日志信息,需要在其 conf/server.yml 配置文件中添加 sql-show: true 配置项。
远程访问测试
- 远程连接 ShardingSphere-Proxy
1 | mysql -h192.168.2.191 -P3309 -uroot -p |
- 查看所有数据库
1 | mysql> show databases; |
- 切换数据库
1 | mysql> use sharding_db; |
- 查看所有表
1 | mysql> show tables; |
- 查询订单数据
1 | mysql> select * from t_order; |
- 查询订单详情数据
1 | mysql> select * from t_order_item; |
提示
执行完上述 select 操作后,可以在 ShardingSphere-Proxy 的日志信息中,查看对应的逻辑 SQL 和真实 SQL,以此判断水平分库是否生效。
SpringBoot 实战使用案例
添加依赖
1 | <properties> |
创建实体类
- 订单实体类(特别注意:分库分表场景下不能使用数据库的自增主键,必须采用分布式全局唯一 ID,否则不同库不同表之间会发生主键冲突)
1 | import com.baomidou.mybatisplus.annotation.IdType; |
- 订单详情实体类(特别注意:分库分表场景下不能使用数据库的自增主键,必须采用分布式全局唯一 ID,否则不同库不同表之间会发生主键冲突)
1 | import com.baomidou.mybatisplus.annotation.IdType; |
创建 Mapper
- 订单 Mapper
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
- 订单详情 Mapper
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
配置数据源
- 创建配置文件(
application.properties),配置数据源
1 | # 应用名称 |
测试代码
- 多表关联数据插入测试
1 |
|
- 测试代码运行后,ShardingSphere-Proxy 运行输出的日志信息如下:
1 | 21:00:10.214 [ShardingSphere-Command-11] INFO ShardingSphere-SQL - Logic SQL: INSERT INTO t_order ( id, order_no, user_id ) VALUES ( 2001638617836711937, '0001', 1 ) |
绑定表使用案例
提示
本节将演示 SpringBoot + MyBatis-Plus 如何通过 ShardingSphere-Proxy 在 水平分库 的基础上结合绑定表实现多表关联数据查询。绑定表是建立在 多表关联 的基础上,其作用是提高多表关联查询的效率。水平分库会根据某个字段(或几个字段)通过特定规则,将数据分散到多个库或表中,每个分片只存储部分数据。例如,可按主键分片:偶数主键记录放入 0 库(或表),奇数主键记录放入 1 库(或表),如图所示。水平分库通常是在水平分表的基础上进一步进行,将原本分散到多张表的数据继续分布到多台数据库服务器上,以提升整体的并发处理能力。完整的案例代码可以直接从 GitHub 下载对应章节 shardingsphere-proxy-lesson-05。
核心概念介绍
- 在 ShardingSphere-Proxy 中,绑定表是指分片规则(包括分库规则和分表规则)完全一致的一组分片表。使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而严重影响查询效率。
- 例如:
t_order表和t_order_item表,均按照order_id进行分片(包括分库和分表),并且使用order_id进行关联,则此两张表互为绑定表关系。 - 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
- 举例说明:
- 如果 SQL 为:
1
SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
- 在不配置绑定表关系时,假设分片键
order_id将数值 10 路由至第 0 片,将数值 11 路由至第 1 片,那么路由后的 SQL 应该为 4 条,它们呈现为笛卡尔积:1
2
3
4
5
6
7SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); - 在配置绑定表关系,并且使用
order_id进行关联后,路由的 SQL 应该为 2 条:1
2
3SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11); - 其中
t_order表由于指定了分片条件,ShardingSphere 将会以它作为整个绑定表的主表。所有路由计算将会只使用主表的策略,那么t_order_item表的分片计算将会使用t_order的条件。
- 如果 SQL 为:
- 总结说明:
- 绑定表的核心目标是保证 ShardingSphere-Proxy 在执行多表关联查询时,能够计算出相同的路由目标,避免:
- 不必要的跨库 JOIN
- 笛卡尔积路由
- 扫描全部数据源
- 绑定表要求多张有关联的表在分库规则和分表规则上完全一致;否则 ShardingSphere-Proxy 无法在 JOIN 时计算出相同的路由,导致不能被视为绑定表。
- 绑定表的核心目标是保证 ShardingSphere-Proxy 在执行多表关联查询时,能够计算出相同的路由目标,避免:
ShardingSphere-Proxy 配置
这里的配置以水平分库为例子,演示如何使用 ShardingSphere-Proxy 提供的分片算法(包括 YAML 和 DistSQL 两种配置方式),其中分片规则如下:
分库规则:
- 订单表(
t_order):t_order逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server_order0);user_id为奇数时,数据插入到订单数据库服务器二(server_order1)。- 这样分库的好处是,同一个用户的订单数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单时效率较高。
- 订单详情表(
t_order_item):t_order_item逻辑表中user_id为偶数时,数据插入到订单数据库服务器一(server_order0);user_id为奇数时,数据插入到订单数据库服务器二(server_order1)。- 这样分库的好处是,同一个用户的订单详情数据,一定会被插入到同一台数据库服务器上,这样查询某个用户的所有订单详情时效率较高。
- 订单表(
分表规则:
- 订单表(
t_order):t_order逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
- 订单详情表(
t_order_item):t_order_item逻辑表中order_no的哈希值为偶数时,数据插入对应数据库服务器的t_order_item0表;order_no的哈希值为奇数时,数据插入对应数据库服务器的t_order_item1表。- 因为
order_no是字符串类型,所以不能直接取模,需要对其进行哈希计算再取模。
- 订单表(
数据库规划:

特别注意
这里希望同一个用户的订单表和订单详情表中的数据都在同一个数据源中,避免跨库关联,因此订单表和订单详情表使用相同的分库规则。由于订单表与订单详情表的分片规则(包括分库规则和分表规则)完全相同,因此这两个表在 ShardingSphere-Proxy 中形成了绑定表关系。无论 ShardingSphere-Proxy 是使用 YAML 配置 还是 DistSQL 配置,都必须注意 ShardingSphere-Proxy 的版本差异。不同版本之间支持的 DistSQL 命令、YAML 配置语法以及参数格式可能存在较大差异,同一份配置在不同版本下可能无法直接执行或行为不一致,因此在编写和迁移配置时必须结合 ShardingSphere-Proxy 具体版本进行验证。
YAML 配置
- 创建或编辑 ShardingSphere-Proxy 的
conf/config-sharding.yaml配置文件,添加以下水平分库的配置内容:
1 | # 逻辑数据库(Schema)的名称 |
- 由于订单表(
t_order)与订单详情表(t_order_item)的分片规则(包括分库规则和分表规则)完全相同,为了提高多表关联查询的效率,上面的配置内容中添加了 ShardingSphere-Proxy 的绑定表配置,如下所示:
1 | # 配置数据分片规则 |
- ShardingSphere-Proxy 水平分库的配置内容添加完成后,需要重启 ShardingSphere-Proxy 服务(假设这里是通过 Docker 部署 ShardingSphere-Proxy 服务),否则配置不会生效
1 | # 重启 Docker 容器 |
- 验证 ShardingSphere-Proxy 中的配置规则是否生效(ShardingSphere-Proxy 启动时会从 YAML 配置文件中加载规则)
1 | # 远程连接 ShardingSphere-Proxy |
1 | -- 查询所有数据库 |
DistSQL 配置
- 创建逻辑数据库(Schema)
1 | -- 创建逻辑数据库(Schema) |
- 添加数据源
1 | -- 添加第一个数据源 |
1 | -- 添加第二个数据源 |
- 创建分片算法
1 | -- 创建取模算法 |
1 | -- 创建哈希取模算法 |
- 创建分布式序列算法
1 | -- 创建 Snowflake 雪花算法 |
- 创建分片规则
1 | -- 创建订单表的分片规则 |
1 | -- 创建订单详情表的分片规则 |
- 创建绑定表
1 | CREATE SHARDING BINDING TABLE RULES ( |
- 验证配置规则是否生效(使用 DistSQL 定义数据源和数据分片规则后,不需要重启 ShardingSphere-Proxy 服务,默认会自动生效)
1 | -- 查询所有数据库 |
查看日志信息
- 查看 ShardingSphere-Proxy 运行的实时日志信息
1 | # 进入容器内,其中环境变量 "env LANG=C.UTF-8" 用于避免容器内显示中文乱码的问题 |
特别注意
在开发或者测试环境中,若希望 ShardingSphere-Proxy 输出详细的日志信息,需要在其 conf/server.yml 配置文件中添加 sql-show: true 配置项。
远程访问测试
- 远程连接 ShardingSphere-Proxy
1 | mysql -h192.168.2.191 -P3309 -uroot -p |
- 查看所有数据库
1 | mysql> show databases; |
- 切换数据库
1 | mysql> use sharding_db; |
- 查看所有表
1 | mysql> show tables; |
- 查询订单数据
1 | mysql> select * from t_order; |
- 查询订单详情数据
1 | mysql> select * from t_order_item; |
提示
执行完上述 select 操作后,可以在 ShardingSphere-Proxy 的日志信息中,查看对应的逻辑 SQL 和真实 SQL,以此判断水平分库是否生效。
SpringBoot 实战使用案例
添加依赖
1 | <properties> |
创建实体类
- 订单实体类(特别注意:分库分表场景下不能使用数据库的自增主键,必须采用分布式全局唯一 ID,否则不同库不同表之间会发生主键冲突)
1 | import com.baomidou.mybatisplus.annotation.IdType; |
- 订单详情实体类(特别注意:分库分表场景下不能使用数据库的自增主键,必须采用分布式全局唯一 ID,否则不同库不同表之间会发生主键冲突)
1 | import com.baomidou.mybatisplus.annotation.IdType; |
创建 VO 类
1 | import lombok.Data; |
创建 Mapper
- 订单 Mapper(特别注意:由于 ShardingSphere-Proxy 中配置了绑定表,因此这里执行多表关联查询时,必须使用分片键(
order_no)进行关联(join),否则会出现笛卡尔积关联或跨库关联,从而严重影响查询效率)
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
- 订单详情 Mapper
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
配置数据源
- 创建配置文件(
application.properties),配置数据源
1 | # 应用名称 |
测试代码
- 多表关联数据查询测试
1 |
|
- 测试代码运行后,ShardingSphere-Proxy 运行输出的日志信息如下:
1 | 16:12:27.288 [ShardingSphere-Command-5] INFO ShardingSphere-SQL - Logic SQL: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no GROUP BY o.order_no |
- 特别注意:
- 如果配置绑定表:测试的结果最终为 4 条 SQL(如上所示), 多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
- 如果不配置绑定表:测试的结果最终为 8 条 SQL(如下所示),多表关联查询会出现笛卡尔积关联,关联查询效率将大大降低。
1
2
3
4
5
6
7
8
916:16:03.942 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order0 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order0 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order0 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
16:16:03.943 [ShardingSphere-Command-14] INFO ShardingSphere-SQL - Actual SQL: server_order0 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC
