0%

shardingsphere初识

shardingsphere

[TOC]

1. 环境

Springboot 3.2.5+ mybatis-flex 1.9.4 + jdk21+ shardingsphere-jdbc-core-spring-boot-starter(5.2.1)

2. 引入maven依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>

3. 设置分片配置

  • application-dev.yml:引入application-sharding.yml配置文件,并屏蔽mybatis-flex的数据源设置

    1
    2
    3
    spring:
    config:
    import: classpath:application-sharding.yml # 引入ShardingSphere分片配置
  • application-sharding.yml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    spring:
    shardingsphere:
    datasource:
    names: ds1
    ds1:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbc-url: jdbc:mysql://192.168.8.1:10086/ruoyi-flex?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: root
    password: root
    hikari:
    minimum-idle: ${spring.datasource.hikari.minimum-idle}
    maximum-pool-size: ${spring.datasource.hikari.maximum-pool-size}
    connection-timeout: ${spring.datasource.hikari.connectionTimeout}
    idle-timeout: ${spring.datasource.hikari.idleTimeout}
    max-lifetime: ${spring.datasource.hikari.maxLifetime}

    # 分片规则配置
    rules:
    sharding:
    # 分片表配置
    tables:
    version_code_change_record:
    # 实际数据节点 - 3张分片表:00、01、02
    actual-data-nodes: ds1.version_code_change_record0$->{0..2}
    # 分表策略
    table-strategy:
    standard:
    sharding-column: version_id
    sharding-algorithm-name: version-id-mod-algorithm
    # 主键生成策略
    key-generate-strategy:
    column: id
    key-generator-name: snowflake

    # 分片算法配置
    sharding-algorithms:
    version-id-mod-algorithm:
    type: MOD
    props:
    sharding-count: 3

    # 主键生成算法配置
    key-generators:
    snowflake:
    type: SNOWFLAKE
    props:
    worker-id: 1

    # 属性配置
    props:
    # 是否开启SQL显示,建议开发环境开启,生产环境关闭
    sql-show: true
    sql-simple: true
    # 是否检查表元数据,生产环境建议关闭以提升启动性能
    check-table-metadata-enabled: true
    # 是否检查重复表,开发阶段开启
    check-duplicate-table-enabled: true

4.自定义分片算法

一般采用基因法对分片键进行一定的”潜规则“设置,使得某一类型的数据能到达统一固定分片上,比如如果用订单表的用户id做分片键,对用户id做基因法操作,使得这个用户的所有订单都到达同一个分片。

再通过分片查询逻辑实现ComplexKeysShardingAlgorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class GenComplexTableAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {

private Properties props;

private String VERSION_ID = "version_id";

private String VERSION_FLOW_NUM = "version_flow_num";

private int shardingCount = 3;

@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
Map<String, Collection<Comparable<?>>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap();

Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());

if(MapUtils.isNotEmpty(columnNameAndShardingValuesMap)){
// 获取用户ID
Collection<Comparable<?>> versionIdCollection = columnNameAndShardingValuesMap.get(VERSION_ID);
//用户分片
if(CollectionUtils.isNotEmpty(versionIdCollection)){
versionIdCollection.stream().findFirst().ifPresent(comparable -> {
long tableNameSuffix = (Long) comparable % shardingCount;
result.add(shardingValue.getLogicTableName() + "_" + tableNameSuffix);
});
}else {
Collection<Comparable<?>> orderSnCollection = columnNameAndShardingValuesMap.get(VERSION_FLOW_NUM);
orderSnCollection.stream().findFirst().ifPresent(comparable -> {
String orderSn = String.valueOf(comparable);
//获取用户基因
String substring = orderSn.substring(Math.max(0, orderSn.length() - 6));
long tableNameSuffix = Long.parseLong(substring) % shardingCount;
result.add(shardingValue.getLogicTableName() + "_" + tableNameSuffix);
});
}
}
return result;
}

@Override
public Properties getProps() {
return props;
}

@Override
public void init(Properties props) {
this.props = props;
}
}

配置说明

  • 所有 ShardingSphere 配置都嵌套在该节点下,包含三大核心模块:datasources(数据源)、rules(功能规则)、props(全局属性)。

    1
    2
    3
    4
    5
    spring:
    shardingsphere:
    datasource:
    rules:
    props:
  • rules:功能规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spring:
    shardingsphere:
    rules: # 功能规则
    sharding:
    # 分片表配置
    tables:
    version_code_change_record: # 要分片的表名
    actual-data-node: ds1.version_code_change_record0$->{0..2} # 实际的数据节点
    database-strategy: # 分库策略

    table-strategy: # 分表策略

    • 标准策略:standard:基于单一字段(分片键)进行分片,是最常用的策略。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      tables:
      t_order:
      actual-data-nodes: ds0.t_order_${0..1}, ds1.t_order_${0..1} # 物理表分布
      table-strategy:
      standard: # 标准策略
      sharding-column: order_id # 分片键:订单ID
      sharding-algorithm-name: order_table_inline # 关联算法
      sharding-algorithms:
      order_table_inline: # 算法定义
      type: INLINE # 内联表达式算法
      props:
      algorithm-expression: t_order_${order_id % 2} # 计算逻辑:order_id取模2
    • 复合策略:complex:基于多个字段联合分片(如同时按 user_idorder_id 分片),适合复杂业务场景。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      tables:
      t_order:
      actual-data-nodes: ds0.t_order_${0..3}, ds1.t_order_${0..3} # 4个物理表
      table-strategy:
      complex: # 复合策略
      sharding-columns: user_id,order_id # 多个分片键
      sharding-algorithm-name: order_table_complex # 关联复合算法
      sharding-algorithms:
      order_table_complex:
      type: CLASS_BASED # 基于自定义类的算法
      props:
      strategy: STANDARD
      algorithm-class-name: com.example.sharding.OrderTableComplexAlgorithm # 自定义算法类
    • hint策略:hint:不依赖 SQL 中的字段,而是通过代码手动指定分片值(如强制路由到某个物理表)。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      tables:
      t_order:
      actual-data-nodes: ds0.t_order_${0..1}
      table-strategy:
      hint: # Hint策略
      sharding-algorithm-name: order_table_hint # 关联Hint算法
      sharding-algorithms:
      order_table_hint:
      type: HINT_INLINE # Hint内联算法
      props:
      algorithm-expression: t_order_${value} # value由代码传入
      1
      2
      3
      4
      5
      6
      7
      8
      // 手动指定分片值为0,路由到t_order_0
      HintManager hintManager = HintManager.getInstance();
      hintManager.addTableShardingValue("t_order", 0); // 指定逻辑表和分片值

      // 执行SQL时,ShardingSphere会根据Hint值路由
      Order order = orderMapper.selectById(1001L);
      hintManager.close(); // 用完关闭

    • 内联策略:inline

    • 不分片策略:none

5. 遇到的问题

  1. 如果工程中没有使用@MapperScan,若使用@MapperScan需制定到具体的mapper实现(com.ruoyi.**.mapper),否则会出现某个类被多次扫描,多次生成bean实例。

  2. snakeyaml版本不兼容问题

shardingsphere-jdbc-core-spring-boot-starter 5.2.1版本与snakeyaml 3.2不兼容,需要使用snakeyaml 1.33,但snakeyaml 1.33springboot 3.2.5不兼容。

所以,强行使用snakeyaml 1.33,并覆盖TagInspectorUnTrustedTagInspectorLoaderOptions三个类。

-------------本文结束感谢您的阅读-------------