Mysql学习笔记:ShardingSphere-JDBC分库分表+读写分离嵌入式实战指南

一、ShardingSphere-JDBC 是什么

ShardingSphere-JDBC 是 ShardingSphere 的嵌入式模式——JDBC 驱动直接嵌入应用内,应用通过它连接数据库,它负责把 SQL 路由到正确的物理库/表。

特性 JDBC(嵌入应用) Proxy(独立服务)
部署方式 引入 Maven 依赖 部署独立 Docker 容器
网络开销 无中间跳转 多一次网络转发
管理成本 随应用部署 独立运维
适用场景 单体应用、微服务 多应用共享、异构语言

本文场景:上一篇我们用 Proxy 搭建了 2 集群 × 1主2从的 MySQL 分片架构,现在用 Spring Boot 应用通过 JDBC 模式直连同一个 MySQL 集群。

如果你还没部署后端 MySQL 集群,请先阅读上一篇 ShardingSphere-Proxy 搭建指南 的 五~六节,先把 6 个 MySQL 跑起来。

二、架构说明

Spring Boot 应用
      │
      ▼
ShardingSphere-JDBC(嵌入应用内)
      │
      │  user_id % 2 → 分库
      │  order_id % 2 → 分表
      │  写→Master,读→Slave
      │
      ├── ds_0 (user_id 偶数)
      │     ├── 22220 Master(写入)
      │     ├── 22221 Slave1(读取)
      │     └── 22222 Slave2(读取)
      │
      └── ds_1 (user_id 奇数)
            ├── 22223 Master(写入)
            ├── 22224 Slave1(读取)
            └── 22225 Slave2(读取)

分片规则:

  • user_id % 2 == 0 → Cluster A(ds_0)
  • user_id % 2 == 1 → Cluster B(ds_1)
  • order_id % 2 == 0 → t_order_0
  • order_id % 2 == 1 → t_order_1

读写分离:

  • INSERT / UPDATE / DELETE → Master
  • SELECT → Slave(轮询负载均衡)

三、环境准备

工具 版本
Java 17+
Spring Boot 4.0.7
ShardingSphere-JDBC 5.5.2
MyBatis Plus 3.5.16(spring-boot4-starter)
MySQL 8.0(6个容器,已在运行)

四、项目搭建

4.1 项目结构

sharding-jdbc-demo/
├── pom.xml
└── src/main/
    ├── java/com/example/sharding/
    │   ├── ShardingJdbcApplication.java
    │   ├── entity/Order.java
    │   ├── mapper/OrderMapper.java
    │   └── service/OrderService.java
    └── resources/
        ├── application.yml
        └── sharding-config.yaml

4.2 依赖配置

关键 Maven 依赖(pom.xml):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.0.7</version>
</parent>

<properties>
    <java.version>17</java.version>
    <shardingsphere.version>5.5.2</shardingsphere.version>
</properties>

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MyBatis Plus(Spring Boot 4.x 专用) -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot4-starter</artifactId>
        <version>3.5.16</version>
    </dependency>

    <!-- ShardingSphere-JDBC(5.5.x ✅ 原生支持 snakeyaml 2.x) -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc</artifactId>
        <version>${shardingsphere.version}</version>
    </dependency>

    <!-- MySQL JDBC 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

⚠️ 版本注意:

  • MyBatis Plus mybatis-plus-spring-boot3-starter 只支持 Spring Boot 3.x,Spring Boot 4.x 必须使用 mybatis-plus-spring-boot4-starter,版本 ≥ 3.5.13
  • ShardingSphere-JDBC 5.5.x 原生支持 snakeyaml 2.x(Spring Boot 3+ 内置),无需额外兼容

4.3 配置数据源与分片规则

application.yml — 使用 ShardingSphere 驱动方式:

spring:
  datasource:
    # 使用 ShardingSphere 提供的 JDBC 驱动
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    # 指定分片配置文件位置(classpath 根目录)
    url: jdbc:shardingsphere:classpath:sharding-config.yaml

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

sharding-config.yaml — 核心分片 + 读写分离配置:

dataSources:
  # ===== Cluster A (ds_0) =====
  ds_0_master:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22220/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123
  ds_0_slave1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22221/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123
  ds_0_slave2:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22222/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123

  # ===== Cluster B (ds_1) =====
  ds_1_master:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22223/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123
  ds_1_slave1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22224/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123
  ds_1_slave2:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:22225/sharding_db?useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root123

rules:
  # ===== 分片规则 =====
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_$->{0..1}.t_order_$->{0..1}
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: db_inline
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: table_inline
    shardingAlgorithms:
      db_inline:
        type: INLINE                                  # Groovy 表达式路由
        props:
          algorithm-expression: ds_${user_id % 2}     # 偶数→ds_0,奇数→ds_1
      table_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 2}

  # ===== 读写分离 =====
  - !READWRITE_SPLITTING
    dataSourceGroups:
      ds_0:
        writeDataSourceName: ds_0_master
        readDataSourceNames:
          - ds_0_slave1
          - ds_0_slave2
      ds_1:
        writeDataSourceName: ds_1_master
        readDataSourceNames:
          - ds_1_slave1
          - ds_1_slave2

props:
  sql-show: true                                     # 控制台打印实际路由 SQL

🔑 关键说明:

  • JDBC 配置中的 ds_0_master 等名称,与 !READWRITE_SPLITTING 中的 writeDataSourceName / readDataSourceNames 对应
  • !SHARDING 中的 actualDataNodes: ds_$->{0..1}.t_order_$->{0..1} 使用 Groovy 表达式语法,$->{} 表示范围
  • 这里用的是读写分离与分片共存:ShardingSphere 先分片决定目标组(ds_0/ds_1),再走读写分离决定是 Master 还是 Slave

五、功能验证

Java 实体类、Mapper、Service 与普通 MyBatis Plus 用法完全一致,唯一区别是数据源配置改为 ShardingSphereDriver,此处不再赘述。

直接用 MySQL 客户端插入数据验证分片效果:

INSERT INTO t_order (order_id, user_id, product_name, status) VALUES
  (1, 1, '商品A', 1),
  (2, 2, '商品B', 1),
  (3, 3, '商品C', 1),
  (4, 4, '商品D', 1);

SELECT * FROM t_order ORDER BY order_id;

应用启动后,控制台输出实际 SQL 路由日志:

# 插入:全部走 Master

INSERT INTO t_order (order_id,user_id,product_name,status) VALUES (?,?,?,?)
  → ds_1_master ::: INSERT INTO t_order_1  VALUES (1, 1, 商品A, 1)    # user_id=1 奇数 → ds_1, order_id=1 奇数 → t_order_1
  → ds_0_master ::: INSERT INTO t_order_0  VALUES (2, 2, 商品B, 1)    # user_id=2 偶数 → ds_0, order_id=2 偶数 → t_order_0
  → ds_1_master ::: INSERT INTO t_order_1  VALUES (3, 3, 商品C, 1)    # user_id=3 奇数 → ds_1, order_id=3 奇数 → t_order_1
  → ds_0_master ::: INSERT INTO t_order_0  VALUES (4, 4, 商品D, 1)    # user_id=4 偶数 → ds_0, order_id=4 偶数 → t_order_0

# 查询:全部走 Slave

SELECT order_id,user_id,product_name,status FROM t_order
  → ds_0_slave1 ::: SELECT ... FROM t_order_0
  → ds_0_slave2 ::: SELECT ... FROM t_order_1
  → ds_1_slave1 ::: SELECT ... FROM t_order_0
  → ds_1_slave2 ::: SELECT ... FROM t_order_1

# 查询结果(4条数据全部返回)
order_id=2, user_id=2, product=商品B
order_id=4, user_id=4, product=商品D
order_id=1, user_id=1, product=商品A
order_id=3, user_id=3, product=商品C

验证结论:

验证项 预期 实际结果
分库:user_id 偶数 → ds_0 ds_0_master ✅
分库:user_id 奇数 → ds_1 ds_1_master ✅
分表:order_id 偶数 → t_order_0 t_order_0 ✅
分表:order_id 奇数 → t_order_1 t_order_1 ✅
读写分离:INSERT → Master Master 节点 ✅
读写分离:SELECT → Slave Slave 节点 ✅
数据完整性 4条数据全量返回 ✅

六、Proxy 与 JDBC 对比总结

对比维度 ShardingSphere-Proxy ShardingSphere-JDBC
部署方式 Docker 独立容器 引入 Maven 依赖
配置位置 global.yaml + database-*.yaml application.yml + sharding-config.yaml
分片配置 dataSourceGroups(5.5.x) 同 Proxy 语法
JDBC 驱动 Proxy 内置 ShardingSphereDriver + jdbc:shardingsphere:classpath:
版本兼容 独立发布 需与 Spring Boot snakeyaml 版本匹配
运维 单独管理 Proxy 容器 随应用部署
性能 多一次网络跳转 直连数据库
适用 多应用共享分片规则 单个应用需要分片

七、总结

通过本文,你用 ShardingSphere-JDBC 完成了:

目标 状态
搭建 Spring Boot 4.0.7 + ShardingSphere-JDBC 项目 ✅
通过 ShardingSphereDriver 加载分片配置 ✅
实现 user_id % 2 分库 ✅
实现 order_id % 2 分表 ✅
实现读写分离(写 Master / 读 Slave) ✅
JUnit 验证分片与路由正确性 ✅

下一步建议:

  • 接入分布式主键(Snowflake 算法)
  • 配置分片事务(@ShardingSphereTransaction)
  • 分片 + 加密规则组合使用
posted @ 2026-10-11 10:09  PC2005-cloud  阅读(28)  评论(0)    收藏  举报