使用 ShardingSphere-JDBC 实现两个 MySQL 数据库中不同表的关联查询,核心在于分片策略的一致性设计 或利用全局表机制,确保关联表的数据能路由到同一物理库中,从而支持本地关联。以下是具体实现步骤和关键配置:
一、场景说明
假设我们有两个 MySQL 数据库 db_order 和 db_user,需要关联查询:
db_order中的订单表t_order(分片键:user_id,按user_id % 2分片到db_order_0和db_order_1)db_user中的用户表t_user(分片键:user_id,按user_id % 2分片到db_user_0和db_user_1)
目标:查询某个用户的所有订单及用户信息(t_order.user_id = t_user.user_id)。
二、核心思路
ShardingSphere-JDBC 支持跨库表的关联查询,但需要保证关联表的分片键路由结果一致 ,或其中一个表为全局表(所有库都存储完整数据),从而让关联操作在本地库完成。
三、具体实现步骤
1. 方案一:分片策略一致(推荐)
若两个表使用相同的分片键和分片算法,ShardingSphere 会将关联查询的 SQL 路由到同一物理库,实现本地关联。
示例配置(Spring Boot):
yaml
spring:
shardingsphere:
datasource:
names: db_order, db_user # 逻辑数据源名称(实际对应两个物理库)
# 配置具体数据源(省略连接信息)
rules:
sharding:
tables:
# 订单表 t_order(属于 db_order 逻辑库)
t_order:
actual-data-nodes: db_order.t_order_$->{0..1} # 分片到 db_order 的 0/1 库
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: order_inline
# 用户表 t_user(属于 db_user 逻辑库)
t_user:
actual-data-nodes: db_user.t_user_$->{0..1} # 分片到 db_user 的 0/1 库
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: user_inline
# 分片算法(user_id 取模)
sharding-algorithms:
order_inline:
type: INLINE
props:
algorithm-expression: t_order_$->{user_id % 2}
user_inline:
type: INLINE
props:
algorithm-expression: t_user_$->{user_id % 2}
关键点:
- 两个表的分片键均为
user_id,且分片算法相同(user_id % 2)。 - 当查询条件包含
user_id时(如WHERE user_id = 123),ShardingSphere 会将t_order路由到db_order.t_order_1(假设123%2=1),同时将t_user路由到db_user.t_user_1。但由于分片键一致,user_id=123在两个库中对应的分片位置相同(都是1),因此实际关联会在各自库的本地表完成。
2. 方案二:全局表(简化路由)
若其中一个表数据量小(如用户表),可将其配置为全局表(所有物理库都存储完整数据),避免跨库关联。
修改配置(将 t_user 设为全局表):
yaml
spring:
shardingsphere:
rules:
sharding:
tables:
t_user:
actual-data-nodes: db_order.t_user, db_user.t_user # 全局表,所有库都存在
type: GLOBAL # 标记为全局表
# 无需分片策略(全局表不参与分片)
效果:
- 无论查询条件如何,
t_user会在所有库中存在完整数据。 - 关联查询时,
t_order路由到目标库(如db_order.t_order_1),t_user直接使用该库中的本地表数据,无需跨库。
3. 编写关联查询 SQL
无论采用哪种方案,SQL 需包含分片键条件,确保路由到同一物理库。
示例 SQL:
sql
SELECT o.order_id, o.amount, u.username
FROM t_order o
JOIN t_user u ON o.user_id = u.user_id
WHERE o.user_id = 123; -- 分片键条件
执行流程:
- ShardingSphere 解析 SQL,提取分片键
user_id=123。 - 路由
t_order到db_order.t_order_1(123%2=1)。 - 路由
t_user到db_user.t_user_1(若为分片表)或直接使用当前库的t_user(若为全局表)。 - 在各自库中执行本地关联,合并结果返回。
四、注意事项
- 分片键一致性:优先保证关联表使用相同分片键和算法,避免全库扫描。
- 全局表适用场景:仅适用于小表(如字典表、用户表),大表会导致存储冗余。
- 性能优化:跨库关联可能影响性能,建议通过冗余字段(如在订单表中存储用户名)减少关联。
- 结果合并:ShardingSphere 会自动合并跨库结果,但复杂关联(如多表、排序、分页)需测试验证。
五、验证与排障
- 开启 ShardingSphere 的 SQL 日志(
props.sql-show: true),观察 SQL 是否路由到正确库。 - 检查关联结果是否完整,避免因分片键缺失导致全库扫描。
- 若关联失败,确认分片策略是否一致,或全局表是否配置正确。
通过以上步骤,ShardingSphere-JDBC 可以高效实现跨 MySQL 数据库不同表的关联查询,核心是通过分片策略或全局表确保数据路由到同一物理库,支持本地关联。