当前位置: 首页 > article >正文

SpringBoot中使用Sharding-JDBC实战(实战+版本兼容+Bug解决)

一、实战

1、引入 ShardingSphere-JDBC 的依赖

https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc/5.5.0

<!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc -->
<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>shardingsphere-jdbc</artifactId>
  <version>5.5.0</version>
  <exclusions>
    <exclusion>
     <groupId>org.apache.shardingsphere</groupId>
      <artifactId>shardingsphere-test-util</artifactId>
    </exclusion>
  </exclusions>
</dependency>

下面是我项目的一些版本信息:

SpringBoot 3.2.4

shardingsphere 5.5.0

2、修改yaml配置文件

application.yaml:
spring:
  profiles:
    active: dev
  main:
    allow-circular-references: true

  datasource:
    # ShardingSphere 对 Driver 自定义,实现分库分表等隐藏逻辑
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    # ShardingSphere 配置文件路径
    url: jdbc:shardingsphere:classpath:shardingsphere-config.yaml
#    driver-class-name: ${quick.datasource.driver-class-name}
#    url: jdbc:mysql://${quick.datasource.host}:${quick.datasource.port}/${quick.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
#    username: ${quick.datasource.username}
#    password: ${quick.datasource.password}
#    hikari:
#      maximum-pool-size: 50

shardingsphere-config.yaml

名字必须相同,前面的 jdbc:shardingsphere:classpath: 是固定写法。

大致的配置结构如上。

dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/quick_pickup?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
    username: root
    password: 123456

# 规则配置
rules:
  - !SINGLE
    tables:
      # 加载全部单表
      - "ds_0.*"
  - !SHARDING
    tables:
      integral_package_order:
        actualDataNodes: ds_0.integral_package_order_${0..15}  # 配置数据表分片规则
        tableStrategy:
          standard:
            shardingColumn: user_id  # 使用 user_id 作为分片键
            shardingAlgorithmName: integral_package_order_table_hash_mod  # 使用自定义的分片算法
    shardingAlgorithms:
      integral_package_order_table_hash_mod:
#        type: HASH_MOD  # 使用 HASH_MOD 算法
#        props:
#          sharding-count: 16  # 设置分片数量为 16
        type: INLINE
        props:
            algorithm-expression: integral_package_order_${user_id % 16}

props:
  sql-show: true  # 控制台打印 SQL 日志,便于调试

# 单机模式 也有集群模式 此处本机选择单机即可 这个必须添加! 不然要报错
mode:
  type: Standalone

其中注意必须加上:

就是两点可能错误:

1.xxx表无法加载

Caused by: org.apache.ibatis.executor.ExecutorException: Error preparing statement. Cause: org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException: Table or view 'store' does not exist. at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:99) ~[mybatis-3.5.14.jar:3.5.14] at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:60) ~[mybatis-3.5.14.jar:3.5.14]

2.不能使用自动的算法这类型的报错

Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Sharding algorithm HASH_MOD initialization failed, reason is: integral_package_order tables sharding configuration can not use auto sharding algorithm.. at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:596) ~[HikariCP-5.0.1.jar:na]

上面截图中HashMod的分片数量里面这个integral_package_order_${order_id % 16}属性应该是16才对,但是还是报错,有大佬有解决可以评论区教教。

设置好需要分片的表,下面就是对表进行水平分片

3、对表进行水平分片

这里我写了一个测试案例可以帮忙我生成16个建表语句:

package com.quick.sharding;

public class IntegralPackageOrderShardingTest {

    // 基础 SQL 模板,使用占位符 `%d` 替换分表的后缀
    public static final String SQL_TEMPLATE = "create table integral_package_order_%d\n" +
            "(\n" +
            "    id                  bigint                              not null comment '主键'\n" +
            "        primary key,\n" +
            "    user_id             bigint unsigned                     not null comment '抢购积分包的用户id',\n" +
            "    integral_package_id bigint unsigned                     not null comment '抢购的积分包id',\n" +
            "    create_time         timestamp default CURRENT_TIMESTAMP not null comment '抢购时间',\n" +
            "    has_use             int                                 null comment '是否使用(0未使用 1已使用)'\n" +
            ")\n" +
            "    comment '积分包订单' charset = utf8mb4\n" +
            "                         row_format = COMPACT;\n" +
            "\n" +
            "create index idx_userId_integral_package_order_%d\n" +
            "    on integral_package_order_%d (user_id);\n";

    public static void main(String[] args) {
        // 生成 16 个分表 SQL
        for (int i = 0; i < 16; i++) {
            // 替换占位符并打印结果
            String sql = String.format(SQL_TEMPLATE, i, i, i);
            System.out.println(sql);
        }
    }
}

 输出如下:

如何运行这些sql即可:

分表完成后理论上是全部配置完成了,但是你会发现运行了没报错,但是发现接口测试,发现了会出现后面的一些问题,这里我先给出解决的配置,就是在你的 WebMvcConfiguration 中加上下面那一段配置。

/**
     * 参考:<a href="https://hafuhafu.com/archives/springboot-jackson-xml-result-json/">...</a>
     * 设置默认的内容类型,并禁用检查Accept请求头,服务端就会忽视原有请求的Accept中的内容协商类型,而按照配置的默认的类型进行响应。
     * 按以下配置的情况下,请求默认总是返回JSON。
     * 如果想让部分接口只返回XML格式的数据,可以在@RequestMapping中配置produces,
     * 如@GetMapping(value = "/api/users",produces = MediaType.APPLICATION_XHTML_XML_VALUE),那个接口就会返回XML格式的数据。
     * @param configurer 配置器
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer
                .defaultContentType(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.APPLICATION_XHTML_XML)
                .ignoreAcceptHeader(true);
    }

4、解决问题

这里只是讲述第三点最后部分解决问题的一些方案,如果不想深入了解可以直接看测试分表那边。

傻眼了,为什么是xml格式,也就是下面这类型的问题:

Spring 5 -jackson-dataformat-xml forces @ResponseBody with XML

结果是XML格式,而不是我们希望的Json格式,我们之前配置的Json序列化失效了吗,这个是我当时的怀疑,其实这个也还是好解决的,只困扰了我一小会,如何去搜,下面先给出解决办法。

我在 WebMvcConfiguration 加了这个一个配置,然后运行解决了

成功输出了Json格式的返回。

下面是我去Github搜的一个解决方案:

shardingsphere-jdbc-5.5.0 causes spring boot to return JSON data as XML · Issue #31203 · apache/shardingsphere · GitHub

这个大佬遇到的问题和我的一样,下面就有很多好友有做评论区解决,大概都聚集在5.5.0版本的shardingsphere让WebMVC的Json转换器失效,因为他自带了一个jackson-dataformat-xml这个东西

这个大佬有提到移除那个依赖,我下面试了这样子做:

结果却报了另外的错误。。。可能是我没完全理解意思,还有另外的策略。

最后我采用了这个策略,再加一个配置

阅读了那个大佬多年工作经验的解决办法,成功加了一个配置解决了那个问题,但是在我的项目里面就多了两个Json序列化,有点在shi山上又多加了几行的感觉。。。

但是还是解决了,但是发现接口文档出现下面这个问题

我们主打的就是一个遇到问题解决问题,再次改造,上面的问题可能是优先级比接口文档高导致接口文档失效,这里就不调整优先级,换了另外一个解决方案,如果不使用接口文档那样子还是可以的。

将上面的配置换成:

/**
     * 参考:<a href="https://hafuhafu.com/archives/springboot-jackson-xml-result-json/">...</a>
     * 设置默认的内容类型,并禁用检查Accept请求头,服务端就会忽视原有请求的Accept中的内容协商类型,而按照配置的默认的类型进行响应。
     * 按以下配置的情况下,请求默认总是返回JSON。
     * 如果想让部分接口只返回XML格式的数据,可以在@RequestMapping中配置produces,
     * 如@GetMapping(value = "/api/users",produces = MediaType.APPLICATION_XHTML_XML_VALUE),那个接口就会返回XML格式的数据。
     * @param configurer 配置器
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer
                .defaultContentType(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.APPLICATION_XHTML_XML)
                .ignoreAcceptHeader(true);
    }

参考了这个文档:内容协商:SpringBoot添加jackson-xml后浏览器返回值的变化 – 败犬不需要安可

mark一下大佬的解决方案。

5、测试分表

这里从测试结合我之前做过的这些博客食用更佳:

对自己关于秒杀功能的一次访谈与实战-CSDN博客

基于之前的秒杀功能的优化(包括Sentinel在SpringBoot中的简单应用)-CSDN博客

1.添加积分包

这里已经是可以看到ShardingSphere生效了。

2.查询所有积分包

3.启用禁用积分包

redis中如下:

可以看到库存已经存在,为100.

4.用户查看所有秒杀积分包信息

5.根据积分包id查询库存

6.用户秒杀抢购积分包

在数据库中可以看出已经存在一条数据了

redis中库存也-1

订单信息也存在

7.用户查看自己的积分包订单

8.禁用积分包

9.删除积分包

删除成功

10.压测

由于上诉是连接服务器的数据库进行测试,下面用本地数据库进行压测

jmeter配置:

开始压测:

如下可见,已经分别分布在各个表上,分表成功:

二、还有一些遇到过的bug

之前用的是下面这个依赖,遇到各种形形色色的问题,可能是版本不服的问题吧,如果有大佬知道怎么解决可以评论区说说,还有上面为什么不能使用HashMod这个算法的原因......

<!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc-core -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
    <version>5.3.2</version>
</dependency>


http://www.kler.cn/a/406753.html

相关文章:

  • Mac 修改默认jdk版本
  • 【数据结构】归并排序 —— 递归及非递归解决归并排序
  • centos 服务器 docker 使用代理
  • html5复习一
  • uni-app 认识条件编译,了解多端部署
  • HarmonyOS笔记5:ArkUI框架的Navigation导航组件
  • 个人笔记本安装CUDA并配合Pytorch使用NVIDIA GPU训练神经网络的计算以及CPUvsGPU计算时间的测试代码
  • Android adb shell dumpsys audio 信息查看分析详解
  • 企业OA管理系统:Spring Boot技术深度探索
  • PTC在电池中的作用
  • 万有引力定律和库仑定律:自然的对称诗篇
  • Android opencv使用Core.hconcat 进行图像拼接
  • 《筑牢安全防线:培养 C++安全编程思维习惯之道》
  • 什么是 C++ 中的模板特化和偏特化?如何进行模板特化和偏特化?
  • Python编程技巧:多变量赋值的优雅艺术
  • 躺平成长-腾讯云数据库(又消失了一次)
  • 打造极致网页体验:HTML与CSS高级实战秘籍
  • 利用Docker容器技术部署发布web应用程序
  • Playwright(Java版) - 7: Playwright 页面对象模型(POM)
  • Vue 是如何实现数据双向绑定的?
  • logstash 解析数组格式json数据:split, json
  • element-plus入门教程:Button
  • 【高阶数据结构】并查集
  • RPC学习
  • 安宝特分享 | 如何利用AR技术革新医疗实践:从远程急救到多学科协作
  • QT QChart+Eigen库绘制线性回归散点图