java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot 3 ShardingSphere-Jdbc分库分表

Spring Boot 3整合ShardingSphere-Jdbc分库分表实战

作者:荒古废体

本文主要介绍了Spring Boot 3整合ShardingSphere-Jdbc分库分表实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

网上找了很多资料,包括官网,使用springboot3shardingsphere-jdbc都无法运行,查了GPT和网上搜索,摸索了一晚上,找到了方案。

1. Maven 依赖

<dependencies>
    <!-- ShardingSphere JDBC 核心依赖 -->
     <dependency>
         <groupId>org.apache.shardingsphere</groupId>
         <artifactId>shardingsphere-jdbc</artifactId>
         <version>5.5.2</version>
     </dependency>

    <!-- Druid 数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-3-starter</artifactId>
        <version>1.2.27</version>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.4.0</version>
    </dependency>
    
     <!-- springboot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.5.5</version>
    </dependency>
</dependencies>

2. application.yml 配置

新版配置分为了两个文件,一个application.yml,另一个是sharding-datasource.yml

官网上是这么说的:

1. 首先 application.yml配置

server:
  port: 9090

spring:
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver # 指定了ShardingSphereDriver 为数据库驱动
    url: jdbc:shardingsphere:classpath:sharding-datasource.yml # 指定classpath的sharding-datasource.yml文件

目录结构:

2. sharding-datasource.yml配置

mode:
  type: Standalone       # ShardingSphere 运行模式,Standalone 表示单机模式,不是集群模式
  repository:
    type: MEMORY         # 元数据存储类型,MEMORY 表示元数据存储在内存中(也可用 JDBC 存储)
dataSources:
  master:                # master名字可以自定义 数据库主库(普通表 写库)
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource  # 使用 Druid 作为真实数据源
    driverClassName: com.mysql.cj.jdbc.Driver                   # MySQL 驱动
    url: jdbc:mysql://localhost:3306/tsuki-chat?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
    username: root
    password: 123456
  slave:                 #slave名字可以自定义 数据库从库(普通表 从库)
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/tsuki-chat?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
    username: root
    password: 123456
  users_master:          # users表数据库主库(用于 users 表分库分表写入操作)
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tsuki-users?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
    username: root
    password: 123456

  users_slave:          # users表数据库从库(用于 users 表分库分表读取操作)
    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/tsuki-users?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
    username: root
    password: 123456

rules:
  # 1️⃣ 全局表(除了 users 表)读写分离规则
  - !READWRITE_SPLITTING
    dataSourceGroups: # 必须用dataSourceGroups,用官网的dataSources会报错
      readwrite_ds:                     # 逻辑数据源名(可自定义)
        writeDataSourceName: master     # 写库
        readDataSourceNames:            # 读库集合
          - slave
        transactionalReadQueryStrategy: PRIMARY  # 事务读策略,PRIMARY 表示事务中读主库
        loadBalancerName: random        # 读库负载均衡策略
    loadBalancers:
      random:                           # 负载均衡算法配置
        type: RANDOM                    # 随机选择读库

  # 2️⃣ 针对users 表读写分离规则
  - !READWRITE_SPLITTING
    dataSourceGroups:
      users_group:                      # users 表逻辑数据源名(可自定义)
        writeDataSourceName: users_master  # 写库
        readDataSourceNames:
          - users_slave # 读库
        transactionalReadQueryStrategy: PRIMARY  # 事务读策略,PRIMARY 表示事务中读主库
        loadBalancerName: random        # 读库负载均衡策略
    loadBalancers:
      random:
        type: RANDOM                    # 随机负载均衡

  # 3️⃣ users 表分表规则
  - !SHARDING
    tables:
      users:
        actualDataNodes: users_group.users_${0..1}   # 物理表名列表,users_0 和 users_1
        tableStrategy:
          standard:
            shardingColumn: id                 # 分表字段
            shardingAlgorithmName: user_algo   # 使用分片算法 user_algo
    shardingAlgorithms:
      user_algo:
        type: INLINE
        props:
          algorithm-expression: users_${id % 2}  # 简单取模算法,将 id % 2 决定插入到 users_0 或 users_1

  # 4️⃣ 其他非分片表(比如 Test、Message 等)走默认读写分离数据源
  - !SINGLE
    tables:
      - "*.*"                             # 匹配所有其他表
    defaultDataSource: readwrite_ds       # 使用逻辑数据源 readwrite_ds(即 tsuki-chat 的读写分离)

props:
  sql-show: true                         # 打印 SQL,便于调试
  check-table: false                      # 不检查表是否存在,防止启动报错
  default-data-source-name: readwrite_ds  # 默认逻辑数据源

3. 配置要点

4. 数据库

数据库首先必须配置主从同步,最好从库禁用插入(这里教程很多,网上自己搭建)
首先有2个数据源,一共4个库
tsuki-chat是我的普通表库,用于存放不用分库分表的库
tsuki-users是我的分库分表库,用于users表分表

users分库分表(我有两张表)

4. 常见问题

  1. 报错 TableNotFoundException → 没有配置 !SINGLE,需要为非分片表指定默认数据源。
  2. 事务中读操作跑到从库 → 配置 transactionalReadQueryStrategy: PRIMARY,保证事务一致性。
  3. 测试数据回滚导致表为空 → 注意是否加了 @Transactional 测试注解。

5. 测试

1. 测试普通表插入

    @Test
    public void test3() {
        DbTest dbTest = new DbTest(1);
        testMapper.insert(dbTest);
    }

输出

2025-09-03T14:34:04.361+08:00  INFO 48308 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO db_test  ( id )  VALUES (  ?  )
2025-09-03T14:34:04.362+08:00  INFO 48308 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: INSERT INTO db_test  ( id )  VALUES (  ?  ) ::: [114514]
2025-09-03T14:34:04.436+08:00  INFO 48308 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} closing ...
2025-09-03T14:34:04.440+08:00  INFO 48308 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} closed

我们可以看到输出了Actual SQL: master ::: INSERT INTO db_test ( id ) VALUES ( ? ) ::: [114514],说明写入走了master
同时从库也有了数据

2. 测试普通表查询

    @Test
    public void test4() {
        DbTest dbTest = testMapper.selectById(114514);
        log.info(dbTest.toString());
    }

输出

2025-09-03T14:39:28.865+08:00  INFO 37376 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT id FROM db_test WHERE id=?
2025-09-03T14:39:28.865+08:00  INFO 37376 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave ::: SELECT id FROM db_test WHERE id=? ::: [114514]
2025-09-03T14:39:28.914+08:00  INFO 37376 --- [           main] c.t.c.server.TestChatServerApplication   : DbTest(id=114514)

我们可以看到输出了Actual SQL: slave ::: SELECT id FROM db_test WHERE id=? ::: [114514],说明读取入走了slave
同时从库也有了数据。
普通表读写测试分离成功

3. 测试users表插入

    @Test
    public void test() {
        List<User> users = generateUsers(10); // 生成10条users数据
        List<BatchResult> insert = userMapper.insert(users);
        log.info("插入成功");
    }

输出

2025-09-03T15:00:10.253+08:00  INFO 47088 --- [           main] ShardingSphere-SQL                       : Actual SQL: users_master ::: INSERT INTO users_1  ( id, username, nickname, signature, email, password, avatar, mobile, login_date, logout_date, login_ip, join_type, sex, status, creator, create_time, updater, update_time, deleted )  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ::: [1756882805969, userUbKYU, nickVpxsL, 签名AWTLp, userUbKYU@example.com, rjctPdFh, https://example.com/avatar/vYJQ.png, 15172505127, 2025-09-02T15:00:05.960025800, 2025-08-31T15:00:05.960025800, 192.168.215.80, 1, 1, 1, system, 2025-08-21T15:00:05.960025800, system, 2025-09-03T15:00:05.960025800, false]
2025-09-03T15:00:10.356+08:00  INFO 47088 --- [           main] c.t.c.server.TestChatServerApplication   : 插入成功

我们可以看到输出了Actual SQL: users_master ::: INSERT INTO users_1 ,说明写入走了users_master
同时从库也有了数据

4. 测试users表查询

    @Test
    public void test2() {
        Page<User> userPage = new Page<User>(1, 8);
        Page<User> selectedPage = userMapper.selectPage(userPage, null);
        selectedPage.getRecords().forEach(user -> log.info(String.valueOf(user.getId())));
    }

输出

2025-09-03T15:07:54.450+08:00  INFO 25284 --- [           main] ShardingSphere-SQL                       : Actual SQL: users_slave ::: SELECT  id,username,nickname,signature,email,password,avatar,mobile,login_date,logout_date,login_ip,join_type,sex,status,creator,create_time,updater,update_time,deleted  FROM users_1 LIMIT ? ::: [8]
2025-09-03T15:07:54.483+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805958
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805960
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805962
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805964
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805966
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805961
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805963
2025-09-03T15:07:54.484+08:00  INFO 25284 --- [           main] c.t.c.server.TestChatServerApplication   : 1756882805965

我们可以看到输出了Actual SQL: users_slave ::: SELECT ,说明读取走了users_slave

✅ 这样配置后:

到此这篇关于Spring Boot 3整合ShardingSphere-Jdbc分库分表实战的文章就介绍到这了,更多相关Spring Boot 3 ShardingSphere-Jdbc分库分表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文