news 2026/4/15 14:47:38

【ShardingJDBC 】【实战】----- SpringBoot3 整合 ShardingJDBC 做分库分表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【ShardingJDBC 】【实战】----- SpringBoot3 整合 ShardingJDBC 做分库分表

文章目录

  • Spring Boot 3 整合 Sharding-JDBC 分库分表实现
    • Nacos配置中心配置
    • Sharding-JDBC 配置类
    • SysMessage 实体类
    • mapper类
    • 服务接口类
    • 服务接口
    • 实现说明

基于spring boot3 + lombok 1.18.30 + mybatis plus 3.5.5 +nacos

Spring Boot 3 整合 Sharding-JDBC 分库分表实现

根据需求,我们需要实现两个核心功能:

  1. 分库:将聊天记录库和用户业务库分离 (提高主业务吞吐量)
  2. 分表:聊天记录表按用户ID(deviceId)分为10个表 (保证单表不超过500万数据量)

下面是核心配置和业务代码实现:

Nacos配置中心配置

在Nacos中需要添加以下配置(dataId可以是application-dev.yml等):

spring:shardingsphere:# 数据源配置datasource:# 定义所有数据源名称,多个用逗号分隔names:user_db,message_db# 用户数据库配置user_db:type:com.zaxxer.hikari.HikariDataSource# 使用Hikari连接池driver-class-name:com.mysql.cj.jdbc.Driver# MySQL驱动类url:jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai# 数据库连接地址username:root# 数据库用户名password:root# 数据库密码# 消息数据库配置message_db:type:com.zaxxer.hikari.HikariDataSource# 使用Hikari连接池driver-class-name:com.mysql.cj.jdbc.Driver# MySQL驱动类url:jdbc:mysql://localhost:3306/message_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai# 数据库连接地址username:root# 数据库用户名password:root# 数据库密码# 分片规则配置rules:sharding:# 表级别的分片配置tables:# 逻辑表名称:sys_messagesys_message:# 实际数据节点:由数据库名+表名表达式组成,这里表示message_db库中的sys_message_0到sys_message_9表actual-data-nodes:message_db.sys_message_${0..9}# 表分片策略table-strategy:# 标准分片策略standard:sharding-column:deviceId# 分片键:使用deviceId字段进行分片sharding-algorithm-name:sys_message_inline# 引用的分片算法名称# 分片算法配置sharding-algorithms:# 与上面引用的算法名称保持一致sys_message_inline:type:INLINE# 算法类型:INLINE表示使用行表达式分片算法props:# 分片算法表达式:# 1. 先计算deviceId的哈希值对10取模# 2. 处理可能出现的负数情况(当哈希值为负数时,取模结果可能为负)# 3. 确保最终结果在0-9之间,对应sys_message_0到sys_message_9表algorithm-expression:sys_message_${deviceId.hashCode() % 10 + 10 >= 10 ? deviceId.hashCode() % 10:deviceId.hashCode() % 10 + 10}

Sharding-JDBC 配置类

packagecom.zgb.config;importorg.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;importorg.apache.shardingsphere.infra.config.algorithm.AlgorithmConfiguration;importorg.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;importorg.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;importorg.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importcom.alibaba.nacos.api.config.annotation.NacosValue;importjavax.sql.DataSource;importjava.sql.SQLException;importjava.util.HashMap;importjava.util.Map;importjava.util.Properties;/** * Sharding-JDBC 配置类,用于配置分库分表规则 * 从Nacos配置中心获取数据源和分片规则配置 */@ConfigurationpublicclassShardingJdbcConfig{/** * 用户业务库数据源配置,从Nacos获取 */@NacosValue("${spring.shardingsphere.datasource.user.url}")privateStringuserDbUrl;@NacosValue("${spring.shardingsphere.datasource.user.username}")privateStringuserDbUsername;@NacosValue("${spring.shardingsphere.datasource.user.password}")privateStringuserDbPassword;@NacosValue("${spring.shardingsphere.datasource.user.driver-class-name}")privateStringuserDbDriverClassName;/** * 聊天记录库数据源配置,从Nacos获取 */@NacosValue("${spring.shardingsphere.datasource.message.url}")privateStringmessageDbUrl;@NacosValue("${spring.shardingsphere.datasource.message.username}")privateStringmessageDbUsername;@NacosValue("${spring.shardingsphere.datasource.message.password}")privateStringmessageDbPassword;@NacosValue("${spring.shardingsphere.datasource.message.driver-class-name}")privateStringmessageDbDriverClassName;/** * 配置ShardingSphere数据源 * * @return 配置好的ShardingSphere数据源 * @throws SQLException 数据库配置异常 */@BeanpublicDataSourcedataSource()throwsSQLException{// 1. 配置数据源Map<String,DataSource>dataSources=newHashMap<>(2);dataSources.put("user_db",createDataSource(userDbUrl,userDbUsername,userDbPassword,userDbDriverClassName));dataSources.put("message_db",createDataSource(messageDbUrl,messageDbUsername,messageDbPassword,messageDbDriverClassName));// 2. 配置分片规则ShardingRuleConfigurationshardingRuleConfig=newShardingRuleConfiguration();// 2.1 配置消息表分表规则shardingRuleConfig.getTables().add(getSysMessageTableRuleConfiguration());// 2.2 配置分库策略(按业务类型)shardingRuleConfig.setDefaultDatabaseShardingStrategy(newStandardShardingStrategyConfiguration("database_type","db_inline"));// 2.3 配置分片算法shardingRuleConfig.getShardingAlgorithms().put("table_inline",newAlgorithmConfiguration("INLINE",getTableShardingAlgorithmProperties()));shardingRuleConfig.getShardingAlgorithms().put("db_inline",newAlgorithmConfiguration("INLINE",getDbShardingAlgorithmProperties()));// 3. 创建并返回ShardingSphere数据源returnShardingSphereDataSourceFactory.createDataSource(dataSources,shardingRuleConfig,newProperties());}/** * 配置sys_message表的分表规则 * * @return 消息表的分片规则配置 */privateShardingTableRuleConfigurationgetSysMessageTableRuleConfiguration(){ShardingTableRuleConfigurationtableRuleConfig=newShardingTableRuleConfiguration("sys_message","message_db.sys_message_${0..9}");// 按deviceId进行分表tableRuleConfig.setTableShardingStrategy(newStandardShardingStrategyConfiguration("deviceId","table_inline"));returntableRuleConfig;}/** * 创建数据源 * * @param url 数据库连接地址 * @param username 数据库用户名 * @param password 数据库密码 * @param driverClassName 数据库驱动类名 * @return 配置好的数据源 */privateDataSourcecreateDataSource(Stringurl,Stringusername,Stringpassword,StringdriverClassName){com.zaxxer.hikari.HikariConfigconfig=newcom.zaxxer.hikari.HikariConfig();config.setJdbcUrl(url);config.setUsername(username);config.setPassword(password);config.setDriverClassName(driverClassName);returnnewcom.zaxxer.hikari.HikariDataSource(config);}/** * 获取表分片算法属性配置 * 按deviceId哈希后取模10,分为10个表 * * @return 表分片算法属性 */privatePropertiesgetTableShardingAlgorithmProperties(){Propertiesprops=newProperties();props.setProperty("algorithm-expression","sys_message_${deviceId.hashCode() % 10 + 10 >= 10 ? deviceId.hashCode() % 10 : deviceId.hashCode() % 10 + 10}");returnprops;}/** * 获取库分片算法属性配置 * 按业务类型区分用户库和消息库 * * @return 库分片算法属性 */privatePropertiesgetDbShardingAlgorithmProperties(){Propertiesprops=newProperties();props.setProperty("algorithm-expression","${database_type == 'message' ? 'message_db' : 'user_db'}");returnprops;}}

SysMessage 实体类

package com.zgb.entity;importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.annotation.TableId;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableName;importlombok.Data;importjava.time.LocalDateTime;/** * 人与AI对话消息实体类 * 对应分表后的sys_message_0到sys_message_9表 */@Data @TableName(value="sys_message",autoResultMap=true)publicclassSysMessage{/** * 消息ID,主键,自增 */@TableId(type=IdType.AUTO)privateLong messageId;/** * 设备ID,用于分表的关键字段 */@TableField("deviceId")privateString deviceId;/** * 会话ID */@TableField("sessionId")privateString sessionId;/** * 消息发送方:user-用户,assistant-人工智能 */privateString sender;/** * AI扮演的角色ID */privateLong roleId;/** * 消息内容 */privateString message;/** * 消息类型 */privateString messageType;/** * 语音文件路径 */privateString audioPath;/** * 状态:1-有效,0-删除 */privateString state;/** * 消息发送时间 */privateLocalDateTime createTime;/** * 数据库类型标识,用于分库的关键字段 * 不在数据库表中,仅用于分库路由 */@TableField(exist=false)privateString databaseType="message";}

mapper类

package com.zgb.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.zgb.entity.SysMessage;importorg.apache.ibatis.annotations.Mapper;importjava.util.List;/** * 消息表数据访问层接口 * 继承MyBatis Plus的BaseMapper,提供基本CRUD操作 */@Mapperpublicinterface SysMessageMapper extends BaseMapper<SysMessage>{/** * 根据设备ID查询消息列表 * * @param deviceId 设备ID * @return 该设备的消息列表 */List<SysMessage>selectByDeviceId(String deviceId);/** * 根据会话ID查询消息列表 * * @param sessionId 会话ID * @return 该会话的消息列表 */List<SysMessage>selectBySessionId(String sessionId);/** * 批量插入消息 * * @param messages 消息列表 * @return 插入成功的记录数 */intbatchInsert(List<SysMessage>messages);}

服务接口类

package com.zgb.service.impl;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.zgb.entity.SysMessage;importcom.zgb.mapper.SysMessageMapper;importcom.zgb.service.SysMessageService;importlombok.RequiredArgsConstructor;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.util.List;/** * 消息服务实现类 * 实现消息的CRUD及相关业务操作 */@Service @RequiredArgsConstructorpublicclassSysMessageServiceImplextends ServiceImpl<SysMessageMapper,SysMessage>implements SysMessageService{privatefinalSysMessageMapper sysMessageMapper;/** * 保存消息 * * @param message 消息实体,必须包含deviceId用于分表路由 * @return 保存成功返回true,否则返回false */@OverridepublicbooleansaveMessage(SysMessage message){// 设置数据库类型为message,确保路由到消息库message.setDatabaseType("message");returnsave(message);}/** * 根据设备ID查询消息 * * @param deviceId 设备ID,用于分表路由 * @return 该设备的消息列表 */@OverridepublicList<SysMessage>getMessagesByDeviceId(String deviceId){returnsysMessageMapper.selectByDeviceId(deviceId);}/** * 根据会话ID查询消息 * Sharding-JDBC会根据SQL中的deviceId进行路由 * * @param sessionId 会话ID * @return 该会话的消息列表 */@OverridepublicList<SysMessage>getMessagesBySessionId(String sessionId){returnsysMessageMapper.selectBySessionId(sessionId);}/** * 批量保存消息 * * @param messages 消息列表,每条消息必须包含deviceId用于分表路由 * @return 保存成功的数量 */@Override @Transactional(rollbackFor=Exception.class)publicintbatchSaveMessages(List<SysMessage>messages){// 设置数据库类型为message,确保路由到消息库messages.forEach(message->message.setDatabaseType("message"));returnsysMessageMapper.batchInsert(messages);}}

服务接口

packagecom.zgb.service;importcom.baomidou.mybatisplus.extension.service.IService;importcom.zgb.entity.SysMessage;importjava.util.List;/** * 消息服务接口 * 提供消息的CRUD及相关业务操作 */publicinterfaceSysMessageServiceextendsIService<SysMessage>{/** * 保存消息 * * @param message 消息实体 * @return 保存成功返回true,否则返回false */booleansaveMessage(SysMessagemessage);/** * 根据设备ID查询消息 * * @param deviceId 设备ID * @return 消息列表 */List<SysMessage>getMessagesByDeviceId(StringdeviceId);/** * 根据会话ID查询消息 * * @param sessionId 会话ID * @return 消息列表 */List<SysMessage>getMessagesBySessionId(StringsessionId);/** * 批量保存消息 * * @param messages 消息列表 * @return 保存成功的数量 */intbatchSaveMessages(List<SysMessage>messages);}

实现说明

  1. 分库策略

    • 通过databaseType字段区分,聊天记录相关表路由到message_db,用户业务表路由到user_db
    • 在消息实体类中默认设置databaseType = "message",确保消息表操作都路由到消息库
  2. 分表策略

    • 聊天记录表sys_messagedeviceId的哈希值取模10分为10个表(sys_message_0sys_message_9
    • 使用INLINE算法实现分片,确保相同设备的消息保存在同一个表中,便于查询
  3. 核心优势

    • 分片规则配置在Nacos中,可动态调整,无需重启服务
    • 使用MyBatis Plus简化数据库操作,开发者无需关心具体操作的是哪个分表
    • 分库分表逻辑对业务代码透明,降低开发复杂度

以上实现满足了将聊天记录与用户业务分离存储,并按用户ID水平拆分聊天记录表的需求,适合高并发、大数据量的聊天场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 0:17:12

大功率防雷器件,低容集成阵列TVS

LC03-6.TBT,LC03-6R2G大功率集成阵列TVS Array 产品概述 TVS二极管是敏感半导体元件板级保护的理想选择。LCO3-6将TVS二极管与整流桥相结合&#xff0c;以单个器件在共模和差分模式下提供瞬态保护。器件的电容最小化(<25pF)&#xff0c;以确保高速线路上正确的信号传输。…

作者头像 李华
网站建设 2026/4/10 21:20:48

​​​​​​​刷爆朋友圈的“香蕉模型”,到底是什么来头?

关注我们 最近AI圈子又变天了 大家都在讨论一个新词 叫做香蕉模型 你可能第一次听说 但在极客圈它已经杀疯了 为什么叫它香蕉 因为它主打的就是 剥皮即食 简单好用且能量巨大 相比于那些庞大的巨无霸模型 香蕉模型更轻量 反应速度更快 而且成本低到令人发指 很多做…

作者头像 李华
网站建设 2026/4/13 12:57:49

[Web自动化] 爬虫之网络请求

9.4 爬虫之网络请求 9.4.1 使用requests库发送HTTP请求 requests库提供了丰富的功能来发送HTTP请求&#xff0c;并处理响应。以下是一些额外的示例和说明。 发送带参数的GET请求&#xff1a; 如果你需要向服务器发送查询参数&#xff0c;可以将它们作为字典传递给params参数。 …

作者头像 李华
网站建设 2026/4/15 12:35:24

08.05.01.tiptop webserver接口篇(制作接口:自定义查询)

本页目录&#xff1a; 1、写代码2、配置3、测试 写代码 修改注册服务接口代码&#xff1a;/u1/topprod/tiptop/aws/4gl/aws_ttsrv2_service.4gl 添加發佈 Service Function 段落 ----------------------- begin waichi001 --------------WHEN "aws_customizeQueryData&…

作者头像 李华
网站建设 2026/4/4 2:13:45

05. 如何实现原理图比较?| OrCAD X Capture CIS 设计小诀窍第二季

OrCAD X Capture CIS设计小诀窍系列--如何实现原理图比较背景介绍&#xff1a;我们在进行原理图设计时&#xff0c;经常需要对原理图进行版本更新。而如果设计师对最新版本的原理图不满意&#xff0c;想要回溯原理图修改了哪些内容&#xff0c;则需要进行原理图比较。而通过Cap…

作者头像 李华
网站建设 2026/4/12 10:47:52

Spring Boot的多环境配置

在开发Spring Boot项目中&#xff0c;如果我们想把自己的项目开源到Github仓库&#xff0c;application.yml中的某些配置比如MySQL、Redis的账户密码&#xff0c;还有的就是现在引入AI之后的一些密钥&#xff0c;可能都不太愿意推送到仓库去。 这个时候&#xff0c;可以通过配…

作者头像 李华