Commit a1f5a0f0d418675def32cf1c09a4148e8e014738

Authored by YunaiV
1 parent 769e5926

feat(infra): 增加可选的 ShardingSphere 分库分表集成材料

script/sharding/README.md 0 → 100644
  1 +# 分库分表(可选接入)
  2 +
  3 +基于 [Apache ShardingSphere-JDBC](https://shardingsphere.apache.org/) 5.5.3 的可选接入材料。项目默认**不启用**:本目录不是 Maven 模块,不参与默认构建,主工程的依赖、配置、业务表都不受影响。
  4 +
  5 +接入后,`master` 主库保持不变,只有 `@DS("sharding")` 的代码,才通过 ShardingSphereDriver 访问 2 库 × 2 表的示例逻辑表 `demo_sharding_order`。
  6 +
  7 +安装、配置、启动验证及使用限制,请阅读项目文档《分库分表》,本文只列出材料及分支适用范围:
  8 +
  9 +- 单体项目 ruoyi-vue-pro:<https://doc.iocoder.cn/sharding/>
  10 +- 微服务项目 yudao-cloud:<https://cloud.iocoder.cn/sharding/>
  11 +
  12 +## 1. 材料清单
  13 +
  14 +| 文件 | 说明 | 单体项目的目标位置 | 微服务项目的目标位置 |
  15 +| --- | --- | --- | --- |
  16 +| `sql/mysql/demo_sharding_order.sql` | 创建 2 个物理库、4 张物理表 | 在 MySQL 中执行 | 在 MySQL 中执行 |
  17 +| `dependencies.xml` | Maven 依赖片段 | `yudao-server/pom.xml` | 服务的 `pom.xml`,例如 `yudao-module-infra-server/pom.xml` |
  18 +| `dynamic-datasource.yaml` | `sharding` 数据源配置片段 | `yudao-server` 的 `application-{profile}.yaml` | 服务的 `application-{profile}.yaml` 或 Nacos 配置 |
  19 +| `src/main/resources/sharding/sharding.yaml` | ShardingSphere 分片规则 | `yudao-module-infra/src/main/resources` | `yudao-module-infra-server/src/main/resources` |
  20 +| `src/main/java/.../shardingdemo/` | 示例 DO、Mapper、Service | `yudao-module-infra/src/main/java` | `yudao-module-infra-server/src/main/java` |
  21 +
  22 +## 2. 分支适用范围
  23 +
  24 +本目录维护在 `master-jdk17` 分支,`master`、`master-jdk25` 分支通过正常的分支同步获得同一份材料,三个分支的接入步骤相同。按各分支 Spring Boot BOM 管理的依赖版本,接入时的差异如下:
  25 +
  26 +| 分支 | JDK | Spring Boot | 差异 |
  27 +| --- | --- | --- | --- |
  28 +| `master` | 8 | 2.7.18 | 添加 `dependencies.xml` 第 2 段的 SnakeYAML 1.33;不能单独升级到 2.x,原因见该文件的注释 |
  29 +| `master-jdk17` | 17 | 3.5.15 | 添加 `dependencies.xml` 第 3 段的 SnakeYAML 2.7 |
  30 +| `master-jdk25` | 25 | 4.1.2 | 添加 `dependencies.xml` 第 3 段的 SnakeYAML 2.7 |
  31 +
  32 +`dependencies.xml` 的第 2、3 段 SnakeYAML 只能按分支选择其一,不能同时添加。
  33 +
  34 +示例 Java 代码只依赖项目已有的 MyBatis Plus、Dynamic Datasource 和多租户组件,不直接引用 ShardingSphere 的类,三个分支无需修改。
... ...
script/sharding/dependencies.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!--
  3 + 分库分表(ShardingSphere-JDBC 5.5.3)的 Maven 依赖片段,不是 Maven 工程,不参与项目构建。
  4 +
  5 + 使用时,将下面的 <dependency> 复制到【最终打包启动】模块的 pom.xml 的 <dependencies> 中:
  6 + - 单体项目:yudao-server/pom.xml
  7 + - 微服务项目:分库分表所在服务的 pom.xml,例如说 yudao-module-infra/yudao-module-infra-server/pom.xml
  8 +
  9 + 复制「1. 所有分支都需要」,再按项目所在分支,从「2.」「3.」中【只选一段】SnakeYAML,两段不能同时添加。
  10 +
  11 + ShardingSphere 5.5.x 是插件化的,shardingsphere-jdbc 只包含内核,以下功能需要显式引入。
  12 + Groovy、Caffeine、Jackson、HikariCP 等传递依赖的版本,继续由项目的 Spring Boot BOM 管理,不要额外覆盖。
  13 +-->
  14 +<dependencies>
  15 +
  16 + <!-- ========== 1. 所有分支都需要 ========== -->
  17 + <dependency>
  18 + <groupId>org.apache.shardingsphere</groupId>
  19 + <artifactId>shardingsphere-jdbc</artifactId> <!-- 内核,提供 ShardingSphereDriver -->
  20 + <version>5.5.3</version>
  21 + </dependency>
  22 + <dependency>
  23 + <groupId>org.apache.shardingsphere</groupId>
  24 + <artifactId>shardingsphere-sharding-core</artifactId> <!-- 数据分片功能,即 !SHARDING 规则 -->
  25 + <version>5.5.3</version>
  26 + </dependency>
  27 + <dependency>
  28 + <groupId>org.apache.shardingsphere</groupId>
  29 + <artifactId>shardingsphere-jdbc-dialect-mysql</artifactId> <!-- MySQL 的 SQL 解析、路由、改写 -->
  30 + <version>5.5.3</version>
  31 + </dependency>
  32 + <dependency>
  33 + <groupId>org.apache.shardingsphere</groupId>
  34 + <artifactId>shardingsphere-infra-url-classpath</artifactId> <!-- 支持 jdbc:shardingsphere:classpath: 加载规则文件 -->
  35 + <version>5.5.3</version>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>org.apache.shardingsphere</groupId>
  39 + <artifactId>shardingsphere-standalone-mode-repository-memory</artifactId> <!-- 单机模式的 Memory 存储 -->
  40 + <version>5.5.3</version>
  41 + </dependency>
  42 + <dependency>
  43 + <groupId>org.apache.shardingsphere</groupId>
  44 + <artifactId>shardingsphere-infra-data-source-pool-hikari</artifactId> <!-- 物理库使用 HikariCP 连接池 -->
  45 + <version>5.5.3</version>
  46 + </dependency>
  47 + <dependency>
  48 + <groupId>org.apache.shardingsphere</groupId>
  49 + <artifactId>shardingsphere-authority-simple</artifactId> <!-- 默认的 ALL_PERMITTED 权限实现,缺少时初始化报 SPI-00001 -->
  50 + <version>5.5.3</version>
  51 + </dependency>
  52 +
  53 + <!-- ========== 2. 仅 master 分支(JDK 8 + Spring Boot 2.7.18):SnakeYAML 1.33 ========== -->
  54 + <!--
  55 + Spring Boot 2.7.18 管理的 SnakeYAML 是 1.30,缺少 ShardingSphere 调用的 LoaderOptions#setCodePointLimit 方法(1.32 起提供),
  56 + 需要显式升级。1.33 是 1.x 的最后一个版本,ShardingSphere 与 Spring Boot 2.7.18 管理的 jackson-dataformat-yaml 2.13.5 都能使用。
  57 + 不能只把 SnakeYAML 升级到 2.x(包括 2.7):2.x 删除了 ParserImpl(StreamReader) 构造方法,jackson-dataformat-yaml 2.13.5 解析 YAML 时
  58 + 会报 NoSuchMethodError;jackson-dataformat-yaml 从 2.15 起才改用 SnakeYAML 2.x,这需要整体升级项目的 Jackson 版本,不在本方案内。
  59 + master-jdk17、master-jdk25 分支不要添加本段,使用下面的「3.」。
  60 + -->
  61 + <dependency>
  62 + <groupId>org.yaml</groupId>
  63 + <artifactId>snakeyaml</artifactId>
  64 + <version>1.33</version>
  65 + </dependency>
  66 +
  67 + <!-- ========== 3. 仅 master-jdk17(Spring Boot 3.5.15)、master-jdk25(Spring Boot 4.1.2)分支:SnakeYAML 2.7 ========== -->
  68 + <!--
  69 + Spring Boot BOM 管理的 SnakeYAML 分别是 2.4、2.6,可以直接使用;这里显式升级到 2.7,ShardingSphere 规则加载、
  70 + Spring Boot 配置加载,以及 BOM 管理的新版 jackson-dataformat-yaml 都能使用。
  71 + master 分支不要添加本段,使用上面的「2.」。
  72 + -->
  73 + <dependency>
  74 + <groupId>org.yaml</groupId>
  75 + <artifactId>snakeyaml</artifactId>
  76 + <version>2.7</version>
  77 + </dependency>
  78 +
  79 +</dependencies>
... ...
script/sharding/dynamic-datasource.yaml 0 → 100644
  1 +# 分库分表的 sharding 数据源配置片段,不能直接作为配置文件使用。
  2 +# 将 sharding 合并到已有的 spring.datasource.dynamic.datasource 下,与 master、slave 同级,其它配置保持不变:
  3 +# - 单体项目:yudao-server 的 application-{profile}.yaml
  4 +# - 微服务项目:对应服务(例如说 yudao-module-infra-server)的 application-{profile}.yaml,或者 Nacos 中该服务的配置
  5 +spring:
  6 + datasource:
  7 + dynamic:
  8 + datasource:
  9 + sharding: # 分库分表数据源,只有 @DS("sharding") 的 Mapper、Service 使用,不影响 master 主库
  10 + lazy: false # 启动时初始化,规则或数据库有误时尽早失败;也避免在异步线程中首次加载 classpath 规则文件
  11 + type: com.zaxxer.hikari.HikariDataSource # 不使用 Druid 连接池,ShardingSphere 的逻辑 SQL 不需要 Druid 解析
  12 + driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
  13 + url: jdbc:shardingsphere:classpath:sharding/sharding.yaml?placeholder-type=environment # 规则文件中的 $${环境变量名::默认值},从环境变量读取
  14 + hikari:
  15 + minimum-idle: 1
  16 + maximum-pool-size: 10 # 逻辑连接数,不能大于 sharding.yaml 中每个物理库的 maximumPoolSize
... ...
script/sharding/sql/mysql/demo_sharding_order.sql 0 → 100644
  1 +-- ----------------------------
  2 +-- 分库分表示例:2 个物理库 × 每库 2 张物理表,对应逻辑表 demo_sharding_order
  3 +--
  4 +-- 1. 分片规则见 src/main/resources/sharding/sharding.yaml:
  5 +-- 分库:ds_${user_id % 2},分表:demo_sharding_order_${user_id.intdiv(2) % 2}
  6 +-- 2. 本脚本使用「库名.表名」,可以在同一个 MySQL 实例上直接执行;
  7 +-- 如果 ds_0、ds_1 是两个不同的 MySQL 实例,则分别执行对应库的语句
  8 +-- 3. 主键 id 由应用的雪花算法生成,所以不使用 AUTO_INCREMENT
  9 +-- 4. 不要在 master 主库创建同名的 demo_sharding_order 表,避免数据源切换失效时“静默”写入主库
  10 +-- ----------------------------
  11 +
  12 +CREATE DATABASE IF NOT EXISTS `yudao_sharding_0` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  13 +CREATE DATABASE IF NOT EXISTS `yudao_sharding_1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  14 +
  15 +-- ----------------------------
  16 +-- ds_0:yudao_sharding_0
  17 +-- ----------------------------
  18 +CREATE TABLE IF NOT EXISTS `yudao_sharding_0`.`demo_sharding_order_0` (
  19 + `id` bigint NOT NULL COMMENT '编号',
  20 + `user_id` bigint NOT NULL COMMENT '用户编号(分片键)',
  21 + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '订单名称',
  22 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  23 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  24 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  25 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  26 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  27 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  28 + PRIMARY KEY (`id`) USING BTREE,
  29 + KEY `idx_user_id` (`user_id`) USING BTREE
  30 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分库分表示例订单表';
  31 +
  32 +CREATE TABLE IF NOT EXISTS `yudao_sharding_0`.`demo_sharding_order_1` (
  33 + `id` bigint NOT NULL COMMENT '编号',
  34 + `user_id` bigint NOT NULL COMMENT '用户编号(分片键)',
  35 + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '订单名称',
  36 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  37 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  38 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  39 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  40 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  41 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  42 + PRIMARY KEY (`id`) USING BTREE,
  43 + KEY `idx_user_id` (`user_id`) USING BTREE
  44 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分库分表示例订单表';
  45 +
  46 +-- ----------------------------
  47 +-- ds_1:yudao_sharding_1
  48 +-- ----------------------------
  49 +CREATE TABLE IF NOT EXISTS `yudao_sharding_1`.`demo_sharding_order_0` (
  50 + `id` bigint NOT NULL COMMENT '编号',
  51 + `user_id` bigint NOT NULL COMMENT '用户编号(分片键)',
  52 + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '订单名称',
  53 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  54 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  55 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  56 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  57 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  58 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  59 + PRIMARY KEY (`id`) USING BTREE,
  60 + KEY `idx_user_id` (`user_id`) USING BTREE
  61 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分库分表示例订单表';
  62 +
  63 +CREATE TABLE IF NOT EXISTS `yudao_sharding_1`.`demo_sharding_order_1` (
  64 + `id` bigint NOT NULL COMMENT '编号',
  65 + `user_id` bigint NOT NULL COMMENT '用户编号(分片键)',
  66 + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '订单名称',
  67 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  68 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  69 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  70 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  71 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  72 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  73 + PRIMARY KEY (`id`) USING BTREE,
  74 + KEY `idx_user_id` (`user_id`) USING BTREE
  75 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '分库分表示例订单表';
... ...
script/sharding/src/main/java/cn/iocoder/yudao/module/infra/shardingdemo/DemoShardingOrderDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.shardingdemo;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
  4 +import com.baomidou.mybatisplus.annotation.IdType;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +/**
  10 + * 分库分表示例订单 DO
  11 + *
  12 + * 逻辑表 demo_sharding_order,按 userId 分布到 2 个库 × 每库 2 张表,规则见 sharding/sharding.yaml
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("demo_sharding_order")
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class DemoShardingOrderDO extends TenantBaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + *
  28 + * 分库分表后无法使用数据库自增,由 MyBatis Plus 的雪花算法生成全局唯一编号
  29 + */
  30 + @TableId(type = IdType.ASSIGN_ID)
  31 + private Long id;
  32 + /**
  33 + * 用户编号,即分片键
  34 + *
  35 + * 新增时必须有值,创建后不允许修改
  36 + */
  37 + private Long userId;
  38 + /**
  39 + * 订单名称
  40 + */
  41 + private String name;
  42 +
  43 +}
... ...
script/sharding/src/main/java/cn/iocoder/yudao/module/infra/shardingdemo/DemoShardingOrderMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.shardingdemo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import com.baomidou.dynamic.datasource.annotation.DS;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 分库分表示例订单 Mapper
  14 + *
  15 + * 在 Mapper 上添加 @DS 注解,保证逻辑表 demo_sharding_order 的 SQL 都使用 sharding 数据源
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Mapper
  20 +@DS(DemoShardingOrderMapper.DATA_SOURCE)
  21 +public interface DemoShardingOrderMapper extends BaseMapperX<DemoShardingOrderDO> {
  22 +
  23 + /**
  24 + * 分库分表的数据源名,对应 spring.datasource.dynamic.datasource.sharding 配置项
  25 + */
  26 + String DATA_SOURCE = "sharding";
  27 +
  28 + default List<DemoShardingOrderDO> selectListByUserId(Long userId) {
  29 + return selectList(new LambdaQueryWrapperX<DemoShardingOrderDO>()
  30 + .eq(DemoShardingOrderDO::getUserId, userId)
  31 + .orderByDesc(DemoShardingOrderDO::getId));
  32 + }
  33 +
  34 + default PageResult<DemoShardingOrderDO> selectPage(PageParam pageParam, Long userId) {
  35 + return selectPage(pageParam, new LambdaQueryWrapperX<DemoShardingOrderDO>()
  36 + .eqIfPresent(DemoShardingOrderDO::getUserId, userId) // 有 userId 时只查询一个分片,否则查询全部分片后归并
  37 + .orderByDesc(DemoShardingOrderDO::getId));
  38 + }
  39 +
  40 +}
... ...
script/sharding/src/main/java/cn/iocoder/yudao/module/infra/shardingdemo/DemoShardingOrderService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.shardingdemo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import com.baomidou.dynamic.datasource.annotation.DS;
  7 +import lombok.RequiredArgsConstructor;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +import org.springframework.util.Assert;
  11 +
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * 分库分表示例订单 Service
  16 + *
  17 + * 1. 带 userId(分片键)的方法,只路由到一个物理库的一张物理表
  18 + * 2. 不带 userId 的方法,会查询全部 4 个物理节点,再由 ShardingSphere 归并结果
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@Service
  23 +@DS(DemoShardingOrderMapper.DATA_SOURCE) // 先切换到 sharding 数据源,再开启 @Transactional 事务
  24 +@RequiredArgsConstructor // 使用构造方法注入,避免 JDK 8 与 JDK 17+ 分支的 @Resource 包名不同
  25 +public class DemoShardingOrderService {
  26 +
  27 + private final DemoShardingOrderMapper demoShardingOrderMapper;
  28 +
  29 + @Transactional(rollbackFor = Exception.class) // 同一个 userId 只在一个物理库,所以是单库的本地事务
  30 + public Long createOrder(Long userId, String name) {
  31 + Assert.notNull(userId, "用户编号(分片键)不能为空");
  32 + DemoShardingOrderDO order = DemoShardingOrderDO.builder().userId(userId).name(name).build();
  33 + demoShardingOrderMapper.insert(order);
  34 + return order.getId();
  35 + }
  36 +
  37 + @Transactional(rollbackFor = Exception.class)
  38 + public int updateOrderName(Long userId, Long id, String name) {
  39 + Assert.notNull(userId, "用户编号(分片键)不能为空");
  40 + // 更新条件带上分片键;更新内容不包含 userId,分片键创建后不允许修改
  41 + DemoShardingOrderDO updateObj = DemoShardingOrderDO.builder().name(name).build();
  42 + return demoShardingOrderMapper.update(updateObj, new LambdaQueryWrapperX<DemoShardingOrderDO>()
  43 + .eq(DemoShardingOrderDO::getUserId, userId)
  44 + .eq(DemoShardingOrderDO::getId, id));
  45 + }
  46 +
  47 + @Transactional(rollbackFor = Exception.class)
  48 + public int deleteOrder(Long userId, Long id) {
  49 + Assert.notNull(userId, "用户编号(分片键)不能为空");
  50 + return demoShardingOrderMapper.delete(new LambdaQueryWrapperX<DemoShardingOrderDO>()
  51 + .eq(DemoShardingOrderDO::getUserId, userId)
  52 + .eq(DemoShardingOrderDO::getId, id));
  53 + }
  54 +
  55 + public DemoShardingOrderDO getOrder(Long userId, Long id) {
  56 + Assert.notNull(userId, "用户编号(分片键)不能为空");
  57 + return demoShardingOrderMapper.selectOne(DemoShardingOrderDO::getUserId, userId,
  58 + DemoShardingOrderDO::getId, id);
  59 + }
  60 +
  61 + public List<DemoShardingOrderDO> getOrderListByUserId(Long userId) {
  62 + Assert.notNull(userId, "用户编号(分片键)不能为空");
  63 + return demoShardingOrderMapper.selectListByUserId(userId);
  64 + }
  65 +
  66 + /**
  67 + * 获得订单分页
  68 + *
  69 + * @param pageParam 分页参数
  70 + * @param userId 用户编号,可为空;为空时查询全部分片,页码越大,归并的数据越多
  71 + * @return 订单分页
  72 + */
  73 + public PageResult<DemoShardingOrderDO> getOrderPage(PageParam pageParam, Long userId) {
  74 + return demoShardingOrderMapper.selectPage(pageParam, userId);
  75 + }
  76 +
  77 +}
... ...
script/sharding/src/main/resources/sharding/sharding.yaml 0 → 100644
  1 +# ShardingSphere-JDBC 5.5.3 分片规则,由 sharding 数据源的 JDBC URL 加载:
  2 +# jdbc:shardingsphere:classpath:sharding/sharding.yaml?placeholder-type=environment
  3 +#
  4 +# 注意:本文件由 ShardingSphere 自己解析,不支持 Spring 的 ${ENV:default} 占位符。
  5 +# 由于 URL 带有 placeholder-type=environment 参数,可以使用 $${环境变量名::默认值} 读取环境变量:
  6 +# 1. 名字与默认值之间的 :: 不能省略,没有默认值时写成 $${环境变量名::}
  7 +# 2. 值会原样替换到本文件中,密码不能包含 $、\、' 字符
  8 +# 3. 不要把真实的账号密码写入本文件、提交到 Git
  9 +
  10 +databaseName: sharding_db # 逻辑库名,只在 ShardingSphere 内部使用
  11 +
  12 +mode:
  13 + type: Standalone # 单机模式,规则只从本文件加载,不依赖注册中心
  14 + repository:
  15 + type: Memory # 元数据保存在内存,不额外创建 H2 等存储
  16 +
  17 +dataSources:
  18 + ds_0:
  19 + dataSourceClassName: com.zaxxer.hikari.HikariDataSource
  20 + driverClassName: com.mysql.cj.jdbc.Driver
  21 + jdbcUrl: $${YUDAO_SHARDING_DS0_URL::jdbc:mysql://127.0.0.1:3306/yudao_sharding_0?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true}
  22 + username: $${YUDAO_SHARDING_DS0_USERNAME::root}
  23 + password: '$${YUDAO_SHARDING_DS0_PASSWORD::}'
  24 + minimumIdle: 1
  25 + maximumPoolSize: 10 # 不能小于 sharding 数据源的 hikari.maximum-pool-size
  26 + ds_1:
  27 + dataSourceClassName: com.zaxxer.hikari.HikariDataSource
  28 + driverClassName: com.mysql.cj.jdbc.Driver
  29 + jdbcUrl: $${YUDAO_SHARDING_DS1_URL::jdbc:mysql://127.0.0.1:3306/yudao_sharding_1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true}
  30 + username: $${YUDAO_SHARDING_DS1_USERNAME::root}
  31 + password: '$${YUDAO_SHARDING_DS1_PASSWORD::}'
  32 + minimumIdle: 1
  33 + maximumPoolSize: 10 # 不能小于 sharding 数据源的 hikari.maximum-pool-size
  34 +
  35 +rules:
  36 + - !SHARDING
  37 + tables:
  38 + demo_sharding_order: # 逻辑表,即 DO 上 @TableName 的表名
  39 + actualDataNodes: ds_$->{0..1}.demo_sharding_order_$->{0..1} # 2 库 × 2 表,共 4 个物理节点
  40 + databaseStrategy:
  41 + standard:
  42 + shardingColumn: user_id
  43 + shardingAlgorithmName: demo_sharding_order_database_inline
  44 + tableStrategy:
  45 + standard:
  46 + shardingColumn: user_id
  47 + shardingAlgorithmName: demo_sharding_order_table_inline
  48 + shardingAlgorithms:
  49 + demo_sharding_order_database_inline:
  50 + type: INLINE
  51 + props:
  52 + algorithm-expression: ds_$->{user_id % 2} # 分库:user_id 对 2 取余
  53 + demo_sharding_order_table_inline:
  54 + type: INLINE
  55 + props:
  56 + algorithm-expression: demo_sharding_order_$->{user_id.intdiv(2) % 2} # 分表:user_id 整除 2 后对 2 取余,与分库错开,4 个节点均匀分布
  57 +
  58 +props:
  59 + sql-show: false # 设置为 true 时,打印逻辑 SQL 与实际路由的 SQL(包含参数值),仅建议本地排查时开启
... ...