~码铃薯~

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ShardingSphere自定义分片策略案例

可以,把这三个接口理解成三种“分片决策方式”:

  • Standard:只看一个分片键,SQL 里能直接看到。
  • Complex:看多个分片键,需要你自己组合计算。
  • Hint:SQL 里没有分片键,靠代码额外传进来。

下面每个都举一个通俗案例。


1. StandardShardingAlgorithm:订单按 order_id 分表

业务场景

订单表 t_order 数据量太大,准备分成 4 张表:

  • t_order_0
  • t_order_1
  • t_order_2
  • t_order_3

规则很简单:按订单 ID 取模

order_id % 4 = 0t_order_01t_order_1,以此类推。

SQL 示例

-- 精准查询:知道订单 ID
SELECT * FROM t_order WHERE order_id = 1001;
-- 1001 % 4 = 1,所以去 t_order_1

-- IN 查询
SELECT * FROM t_order WHERE order_id IN (1001, 1002, 1003);
-- 分别路由到 t_order_1、t_order_2、t_order_3

-- 范围查询
SELECT * FROM t_order WHERE order_id BETWEEN 1001 AND 1010;
-- 范围跨多张表,需要返回可能涉及的表

自定义算法代码

public class OrderStandardAlgorithm implements StandardShardingAlgorithm<Long> {

    // 处理 =、IN
    @Override
    public String doSharding(Collection<String> tables,
                             PreciseShardingValue<Long> shardingValue) {
        Long orderId = shardingValue.getValue();
        String targetTable = "t_order_" + (orderId % 4);
        if (tables.contains(targetTable)) {
            return targetTable;
        }
        throw new UnsupportedOperationException("没有找到表: " + targetTable);
    }

    // 处理 BETWEEN、>、<
    @Override
    public Collection<String> doSharding(Collection<String> tables,
                                         RangeShardingValue<Long> shardingValue) {
        // 简单写法:范围查询返回所有表,避免漏数据
        // 实际生产建议根据范围上下界计算真正需要的表
        return tables;
    }
}

配置示例

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds0.t_order_$->{0..3}
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: order-standard
        sharding-algorithms:
          order-standard:
            type: CLASS_BASED
            props:
              strategy: STANDARD
              algorithmClassName: com.example.OrderStandardAlgorithm

通俗理解

就像快递分拣:
只看一个“订单号”,尾号是几就扔到几号柜子。
这就是 Standard:单分片键,SQL 里直接带 order_id


2. ComplexKeysShardingAlgorithm:订单按 user_id + order_id 组合分表

业务场景

还是订单表,但业务希望:

  • 同一个用户的订单尽量集中;
  • 同时订单也要分散到多张表。

于是分片键有两个

  • user_id
  • order_id

分片规则:(user_id + order_id) % 4,分到 t_order_0 ~ t_order_3

SQL 示例

-- 两个分片键都有,可以精确算出表
SELECT * FROM t_order WHERE user_id = 123 AND order_id = 456;
-- (123 + 456) % 4 = 579 % 4 = 3,去 t_order_3

-- 只带 user_id,无法唯一确定,需要返回所有可能表
SELECT * FROM t_order WHERE user_id = 123;

-- 只带 order_id,也无法唯一确定
SELECT * FROM t_order WHERE order_id = 456;

自定义算法代码

public class OrderComplexAlgorithm implements ComplexKeysShardingAlgorithm<Long> {

    @Override
    public Collection<String> doSharding(Collection<String> tables,
                                         Collection<ShardingValue> shardingValues) {
        Map<String, Long> valueMap = new HashMap<>();

        for (ShardingValue sv : shardingValues) {
            if (sv instanceof PreciseShardingValue) {
                PreciseShardingValue<Long> precise = (PreciseShardingValue<Long>) sv;
                valueMap.put(precise.getColumnName(), precise.getValue());
            }
        }

        Long userId = valueMap.get("user_id");
        Long orderId = valueMap.get("order_id");

        // 两个键都有,精确路由
        if (userId != null && orderId != null) {
            String targetTable = "t_order_" + ((userId + orderId) % 4);
            return Collections.singletonList(targetTable);
        }

        // 缺少任意一个键,无法精确路由,返回所有表
        return tables;
    }
}

配置示例

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds0.t_order_$->{0..3}
            table-strategy:
              complex:
                sharding-columns: user_id, order_id
                sharding-algorithm-name: order-complex
        sharding-algorithms:
          order-complex:
            type: CLASS_BASED
            props:
              strategy: COMPLEX
              algorithmClassName: com.example.OrderComplexAlgorithm

通俗理解

就像寄快递时,不仅看订单号,还要看用户所在城市。
两个条件一起决定包裹去哪个仓库。
这就是 Complex:多分片键,需要自己组合判断。


3. HintShardingAlgorithm:多租户按 tenant_id 分表,但 SQL 里不带 tenant_id

业务场景

SaaS 系统,每个租户一张订单表:

  • 租户 101:t_order_101
  • 租户 102:t_order_102
  • 租户 103:t_order_103

但是 SQL 里不写租户 ID,因为租户信息在登录后放在 ThreadLocal 或请求上下文里。

比如当前登录用户属于租户 101,代码里强制路由到 t_order_101

SQL 示例

-- SQL 里没有 tenant_id
SELECT * FROM t_order WHERE order_id = 1001;

代码里设置 Hint

HintManager hintManager = HintManager.getInstance();
hintManager.setShardingValue("tenant_id", 101L);

// 执行 SQL,ShardingSphere 会从 Hint 中取 tenant_id
jdbcTemplate.query("SELECT * FROM t_order WHERE order_id = 1001", ...);

hintManager.close();

自定义算法代码

public class TenantHintAlgorithm implements HintShardingAlgorithm<Long> {

    @Override
    public Collection<String> doSharding(Collection<String> tables,
                                         HintShardingValue<Long> hintValue) {
        Long tenantId = hintValue.getValues().iterator().next();
        String targetTable = "t_order_" + tenantId;

        if (tables.contains(targetTable)) {
            return Collections.singletonList(targetTable);
        }
        throw new UnsupportedOperationException("表不存在: " + targetTable);
    }
}

配置示例

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds0.t_order_$->{101..103}
            table-strategy:
              hint:
                sharding-algorithm-name: tenant-hint
        sharding-algorithms:
          tenant-hint:
            type: CLASS_BASED
            props:
              strategy: HINT
              algorithmClassName: com.example.TenantHintAlgorithm

通俗理解

就像快递单上没写“哪个小区”,但系统后台知道你现在属于哪个小区,强制把包裹分到那个小区。
这就是 Hint:分片键不在 SQL 中,由外部条件决定。


总结对比

接口 分片键数量 分片键位置 典型场景 通俗类比
StandardShardingAlgorithm 1 个 SQL 里 订单按 order_id 分表 只看订单号尾号
ComplexKeysShardingAlgorithm 多个 SQL 里 订单按 user_id + order_id 分表 同时看用户和订单号
HintShardingAlgorithm 0 个 SQL 外 多租户、灰度、强制路由 系统后台偷偷指定区域

选择原则:

  • 只有一个分片键,用 Standard
  • 有多个分片键,用 Complex
  • SQL 里根本看不到分片键,用 Hint
posted on 2026-09-20 16:57  ~码铃薯~  阅读(4)  评论(0)    收藏  举报