ShardingJDBC 有哪些分片策略,你用的哪个?
结论:ShardingSphere 5.x 把分片拆成两层——分片算法(Sharding Algorithm)负责「算出分片值」,分片策略(Sharding Strategy)负责「用哪个列、配哪个算法」。内置算法有
INLINE、MOD、HASH_MOD、VOLUME_RANGE、BOUNDARY_RANGE、AUTO_INTERVAL等;4.x 时代则直接叫 Inline、Standard、Complex、Hint、None 五种策略。生产上最常用的是MOD、HASH_MOD配standard,特殊规则写CLASS_BASED自定义。
一、策略与算法对照
| 版本 | 概念 | 常见取值 |
|---|---|---|
| 5.x | 分片策略 strategy | standard、complex、hint、none |
| 5.x | 分片算法 algorithm | INLINE、MOD、HASH_MOD、VOLUME_RANGE、BOUNDARY_RANGE、AUTO_INTERVAL、CLASS_BASED |
| 4.x | 策略类型 | inline、standard、complex、hint、none |
| 策略 | 适用 SQL 形态 | 说明 |
|---|---|---|
standard | =、IN、BETWEEN 单列 | 最常用,单分片键 |
complex | 多列组合分片 | 必须自定义算法 |
hint | SQL 不带分片键 | 由 HintManager 强制指定 |
none | 广播表、单库 | 不做分片 |
二、YAML 配置
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.0.0.11:3306/order_db
username: app
password: ${ORDER_DB_PWD}
ds1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.0.0.12:3306/order_db
username: app
password: ${ORDER_DB_PWD}
rules:
sharding:
binding-tables:
- t_order,t_order_item
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..7}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: db_mod
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: tbl_hash_mod
t_order_item:
actual-data-nodes: ds$->{0..1}.t_order_item_$->{0..7}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: db_mod
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: tbl_hash_mod
sharding-algorithms:
db_mod:
type: MOD
props:
sharding-count: 2
tbl_hash_mod:
type: HASH_MOD
props:
sharding-count: 8
三、自定义算法
public class OrderTimeShardingAlgorithm
implements StandardShardingAlgorithm<LocalDateTime> {
private static final LocalDateTime CUTOVER = LocalDateTime.of(2025, 1, 1, 0, 0);
@Override
public String doSharding(Collection<String> available,
PreciseShardingValue<LocalDateTime> value) {
String suffix = value.getValue().isAfter(CUTOVER) ? "_new" : "_old";
return available.stream()
.filter(t -> t.endsWith(suffix))
.findFirst()
.orElseThrow(() -> new IllegalStateException("无可用分片: " + available));
}
@Override
public Collection<String> doSharding(Collection<String> available,
RangeShardingValue<LocalDateTime> value) {
return available; // 范围查询扇出全部分片
}
@Override
public String getType() {
return "ORDER_TIME";
}
}
注册时把算法 type 改为 CLASS_BASED,并用 props 指定 strategy: STANDARD 与 algorithmClassName。
四、常见追问
Q1:为什么不用 inline 表达式?
INLINE 写法简洁(t_order_$->{user_id % 8}),但每次路由都要做表达式求值,压测下开销明显;且不支持范围分片、不便于统一治理。生产更推荐 MOD、HASH_MOD 或自定义算法。
Q2:分片后哪些 SQL 不支持?
跨分片的 UNION、部分子查询、CASE WHEN 中引用分片键、未配绑定表的跨库 JOIN、以及部分形态的 INSERT ... SELECT。上线前用 sql-show 逐条核对改写结果。
Q3:SQL 里没有分片键怎么办?
用 HintManager 强制路由:HintManager.getInstance().addDatabaseShardingValue("t_order", 3),适合后台任务或按租户批量处理。用完务必 close(),它绑在线程上。
小结
- 5.x 是「策略选列 + 算法算值」两层结构,4.x 把两者合在一起叫策略。
- 高频场景用
MOD、HASH_MOD配standard,特殊规则写CLASS_BASED。 - 上线前打开
sql-show,确认每条 SQL 的改写与路由都符合预期。