1、ComplexShardingStrategy ?
2、HintShardingAlgorithm ?
3、StandardShardingAlgorithm?
下面我来详细拆解这三种分片策略,帮你更好地理解它们的区别。
总的来说,这三种策略分别解决了不同层面的路由问题:Standard 应对单维精确与范围查询,Complex 负责多维联合路由,Hint 则实现了代码层面的强制干预。你可以先通过这个速查表快速了解它们的核心区别:
| 特性维度 | 🎯 标准分片策略 (Standard) | 🧩 复合分片策略 (Complex) | ✨ 强制路由分片策略 (Hint) |
|---|---|---|---|
| 分片键数量 | 单一分片键-28 | 多个分片键-28 | 无分片键,或忽略SQL中的分片键-12 |
| 操作符支持 | =, IN, BETWEEN AND, >, <, >=, <=-28 | =, IN, BETWEEN AND, >, <, >=, <=-28 | 通过代码指定路由目标,不受SQL操作符限制-12 |
| 核心实现 | 需实现 PreciseShardingAlgorithm (必选) 和 RangeShardingAlgorithm (可选)-28 | 需实现 ComplexKeysShardingAlgorithm 接口,处理复合逻辑-28 | 需实现 HintShardingAlgorithm 接口,通过 HintManager 注入分片值-28 |
| 灵活性 | 中 | 高 | 极高 |
| 实现复杂度 | 低 | 中 | 低 (API使用简单) |
| 核心优势 | 能高效处理单键的范围查询,实现更精确的路由 | 可根据多字段组合,实现强大的自定义路由 | 可强制指定路由目标,突破SQL限制,实现灵活干预 |
| 主要局限 | 无法处理多字段联合分片-21 | 需自行处理多分片键的复杂逻辑,有全表扫描风险- | API侵入性强,过度使用会破坏架构的清晰度-21 |
1. 🎯 标准分片策略 (Standard)
概念、作用与功能
正如其名,这是最标准、最常用的策略,是分库分表的“基本款”。针对的是只有一个分片键,但查询条件多样的场景。它不仅能处理 = 和 IN 这样的精确查找,还能智能处理 BETWEEN AND 和 > < 这类范围查询。
与复杂逻辑都塞在一个类里的复合策略不同,Standard 策略通过 PreciseShardingAlgorithm (处理精确查询)-36 和 RangeShardingAlgorithm (处理范围查询)-36 两个更细粒度的算法接口,实现了关注点分离,让代码逻辑更清晰。
优缺点分析
-
👍 优点:支持复杂SQL操作符,处理范围查询和精确查询的性能都很高-21。
-
👎 缺点:只能基于一个字段分片。如果你的查询条件里经常同时出现
user_id和order_id,用这个策略就爱莫能助了-21。
实战演示
下面是一个完整的代码示例,展示如何实现一个自定义的标准分片算法,根据 order_id 的奇偶性将其路由到不同的数据库表。
1. 实现自定义分片算法
创建一个Java类,实现StandardShardingAlgorithm接口-36。ShardingSphere会自动根据SQL操作符,调用对应的doSharding方法。
public class MyStandardShardingAlgorithm implements StandardShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
// 处理 SQL 中的 = 和 IN 操作符
Long orderId = shardingValue.getValue();
String suffix = String.valueOf(orderId % 2);
for (String targetName : availableTargetNames) {
if (targetName.endsWith(suffix)) {
return targetName;
}
}
return null;
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
// 处理 SQL 中的 BETWEEN AND、>、< 等范围操作符
Collection<String> result = new LinkedHashSet<>();
Range<Long> valueRange = shardingValue.getValueRange();
for (Long i = valueRange.lowerEndpoint(); i <= valueRange.upperEndpoint(); i++) {
String suffix = String.valueOf(i % 2);
for (String targetName : availableTargetNames) {
if (targetName.endsWith(suffix)) {
result.add(targetName);
}
}
}
return result;
}
// 其他必要方法(init, getProps等)略...
}
2. 配置分片策略
在配置文件中指定strategy: STANDARD,并设置分片键order_id-36。
yaml
# 分片算法定义
shardingAlgorithms:
standard-algorithm:
type: CLASS_BASED
props:
strategy: STANDARD
algorithmClassName: com.example.MyStandardShardingAlgorithm
# 表策略配置
t_order:
actualDataNodes: ds0.t_order_${0..1}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: standard-algorithm
2. 🧩 复合分片策略 (Complex)
概念、作用与功能
当业务无法通过单一字段决定数据归属时,就需要复合分片策略。它支持使用两个及以上的字段作为联合分片键-28-1。因多分片键关系复杂,ShardingSphere不提供默认实现,而是将完整的分片键值组合直接交给开发者,给予最大的灵活度-。
优缺点分析
-
👍 优点:支持多字段联合分片,能实现更贴近业务的、复杂的路由逻辑-21。
-
👎 缺点:需要自行处理多分片键组合逻辑,复杂度高;实现不当的SQL可能引发全库表路由,造成性能问题-。
实战演示
这个示例展示了如何根据 user_id 和 region_code(区域码)两个字段,共同决定数据最终路由到哪张表。
1. 实现复合分片算法
创建一个Java类,实现ComplexKeysShardingAlgorithm接口。
public class MyComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
ComplexKeysShardingValue<Long> shardingValue) {
// 获取所有分片键的列名和对应的值
Map<String, Collection<Long>> columnValuesMap = shardingValue.getColumnNameAndShardingValuesMap();
Collection<Long> userIds = columnValuesMap.get("user_id");
Collection<Long> regionCodes = columnValuesMap.get("region_code");
Set<String> result = new HashSet<>();
for (Long userId : userIds) {
for (Long regionCode : regionCodes) {
// 自定义复杂分片逻辑,例如:按user_id取模,再根据region_code决定表后缀
String suffix = ((userId % 4) + (regionCode % 2)) % 2 + "";
for (String targetName : availableTargetNames) {
if (targetName.endsWith(suffix)) {
result.add(targetName);
}
}
}
}
return result;
}
// 其他必要方法略...
}
2. 配置分片策略
在配置文件中指定strategy: COMPLEX,并列出所有分片键shardingColumns: user_id, region_code-35。
yaml
# 分片算法定义
shardingAlgorithms:
complex-algorithm:
type: CLASS_BASED
props:
strategy: COMPLEX
algorithmClassName: com.example.MyComplexKeysShardingAlgorithm
# 表策略配置
t_user_log:
actualDataNodes: ds0.t_user_log_${0..1}
tableStrategy:
complex:
shardingColumns: user_id, region_code
shardingAlgorithmName: complex-algorithm
注意:复合分片策略对开发者的要求较高,分片逻辑不当容易导致全库表扫描,严重影响性能。上线前务必做好充分测试-。
3. ✨ 强制路由分片策略 (Hint)
概念、作用与功能
这是为解决“分片键不在SQL中”这类棘手问题而生的“秘密武器”。当分片信息需要从外部(如用户会话、业务上下文)获取时,常规策略就失效了。Hint策略允许你在代码中通过HintManager手动指定路由目标-12,使SQL能无视原有逻辑,直接路由到指定节点-50。
优缺点分析
-
👍 优点:解决了无分片键字段的SQL路由难题,可实现强制主库路由(读写分离)、指定库表测试等精细操作-50。
-
👎 缺点:业务代码侵入性强,需要手动管理
HintManager的生命周期-21。使用不当可能绕过精心设计的分片逻辑,造成数据分布混乱。
实战演示
下面是一个综合示例,展示了Hint的两种常见用法:一种是强制路由到指定数据节点;另一种是在读写分离场景下,强制查询走主库以保证数据实时性。
1. 实现Hint分片算法
创建一个Java类,实现HintShardingAlgorithm接口。
public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
HintShardingValue<Long> shardingValue) {
Collection<String> result = new ArrayList<>();
// 获取通过 HintManager 注入的分片值
for (Long value : shardingValue.getValues()) {
for (String targetName : availableTargetNames) {
if (targetName.endsWith(String.valueOf(value % 2))) {
result.add(targetName);
}
}
}
return result;
}
// 其他必要方法略...
}
2. 配置分片策略
在配置文件中指定strategy: HINT,将其定义为Hint策略。
yaml
# 分片算法定义
shardingAlgorithms:
hint-algorithm:
type: CLASS_BASED
props:
strategy: HINT
algorithmClassName: com.example.MyHintShardingAlgorithm
# 表策略配置
t_order:
actualDataNodes: ds0.t_order_${0..1}
tableStrategy:
hint:
shardingAlgorithmName: hint-algorithm
3. 在业务代码中使用 HintManager
在代码中通过HintManager来实际控制路由。
// 场景一:强制路由到指定库表
@Test
public void testHintInsert() {
try (HintManager hintManager = HintManager.getInstance()) {
// 指定路由到数据库后缀为1,表后缀为0的节点
hintManager.addDatabaseShardingValue("t_order", 1L);
hintManager.addTableShardingValue("t_order", 0L);
// 执行数据插入操作
orderMapper.insert(order);
}
}
// 场景二:强制读写分离下的主库路由
@Test
public void testForceMaster() {
try (HintManager hintManager = HintManager.getInstance()) {
// 强制本次查询走主库,避免主从同步延迟
hintManager.setMasterRouteOnly();
List<Order> orders = orderMapper.selectRecentOrders();
}
}
💎 总结与建议
归根结底,这三种策略服务于不同的分片场景。我建议你可以参考下面这个思路来选择:
-
优先选择标准策略:如果你的分片逻辑主要围绕一个业务字段展开,并且需要支持范围查询,
StandardShardingAlgorithm是最佳选择。 -
考虑复合策略:当业务规则强依赖多个字段(如
(user_id, order_id))才能确定数据位置时,再选用ComplexShardingAlgorithm。 -
保留 Hint 作为秘密武器:当分片键无法从SQL中获取,或在读写分离等特殊场景下需要“强制干预”路由时,
Hint是最佳解决方案,但切记不宜过度使用。

1829

被折叠的 条评论
为什么被折叠?



