ShardingSphere 分片:Apache 分布式数据库生态

FreeGuideOnline 最新 2026-06-30

xml org.apache.shardingsphere shardingsphere-jdbc-core-spring-boot-starter 5.4.1 com.mysql mysql-connector-j


#### 配置分片规则
在 `application.yml` 中定义数据源和分片规则。示例按 `order_id` 分库分表,使用行表达式简化配置。

```yaml
spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC
        username: root
        password: root
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC
        username: root
        password: root
    rules:
      sharding:
        # 分片算法配置
        sharding-algorithms:
          database-inline:
            type: INLINE
            props:
              algorithm-expression: ds${order_id % 2}
          table-inline:
            type: INLINE
            props:
              algorithm-expression: t_order_${order_id % 2}
        # 表规则
        tables:
          t_order:
            actual-data-nodes: ds${0..1}.t_order_${0..1}
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: database-inline
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: table-inline
    props:
      sql-show: true   # 开发时打印 SQL 便于调试

编写实体与数据操作

使用 Spring Data JPA 或 MyBatis 均可。以下为 JPA 示例:

@Entity
@Table(name = "t_order")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long orderId;
    private Long userId;
    private String status;
    // getters / setters 省略
}

Repository:

public interface OrderRepository extends JpaRepository<Order, Long> {
}

测试分片效果

编写测试插入不同 order_id 的数据,观察数据是否路由到正确的库和表:

@SpringBootTest
class OrderTest {
    @Autowired
    private OrderRepository repository;

    @Test
    void testInsert() {
        for (long i = 1; i <= 4; i++) {
            Order order = new Order();
            order.setOrderId(i);
            order.setUserId(100 + i);
            order.setStatus("NEW");
            repository.save(order);
        }
    }
}

打开 SQL 日志,应能看到 Actual SQL 指向 ds0.t_order_1ds1.t_order_0 等节点。


进阶分片策略配置

行表达式分片

使用 INLINE 算法并提供 Groovy 表达式,如上例 ds${order_id % 2},简洁但仅支持简单取模。

自定义精准分片

当分片逻辑复杂时需要自定义算法。实现 PreciseShardingAlgorithm 接口:

public class CustomDatabasePreciseAlgorithm implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        // 自定义规则,比如取哈希后映射到库名
        long hash = shardingValue.getValue() % 4;
        String target = "ds" + hash;
        if (availableTargetNames.contains(target)) {
            return target;
        }
        throw new UnsupportedOperationException();
    }
}

在配置中引用该算法:

sharding-algorithms:
  custom-db:
    type: CLASS_BASED
    props:
      strategy: standard
      algorithmClassName: com.example.CustomDatabasePreciseAlgorithm

范围分片

对于 BETWEEN AND 查询,需要实现 RangeShardingAlgorithm。内置 VOLUME_RANGE 算法支持基于范围的分片,但更常见的做法是结合自定义算法。

复合分片

当使用多个分片键时,实现 ComplexKeysShardingAlgorithm,在配置的 database-strategytable-strategy 中指定 complex 策略。

Hint 强制路由

在某些场景下,分片键不在 SQL 中,需要通过编码指定路由。使用 HintManager

HintManager hintManager = HintManager.getInstance();
hintManager.addDatabaseShardingValue("t_order", 1);   // 强制路由到 ds1
hintManager.addTableShardingValue("t_order", 0);      // 强制路由到 t_order_0
// 执行 SQL
hintManager.close();   // 务必关闭,避免线程泄露

对应的 Hint 算法需实现 HintShardingAlgorithm


分布式场景中的常见问题

分布式主键生成

分片后不能沿用数据库自增主键。ShardingSphere 内置雪花算法(Snowflake)和 UUID 生成器。配置如下:

rules:
  sharding:
    key-generators:
      snowflake:
        type: SNOWFLAKE
    tables:
      t_order:
        key-generate-strategy:
          column: order_id
          key-generator-name: snowflake