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

分库分表之实战-sharding-JDBC

大家好,我是工藤学编程 🦉一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷【SpringBoot实战系列】Sharding-Jdbc实现分库分表到分布式ID生成器Snowflake自定义wrokId实战
环境搭建大集合环境搭建大集合(持续更新)
分库分表分库分表下的 ID 冲突问题与雪花算法讲解

前情摘要:

1、数据库性能优化
2、分库分表之优缺点分析
3、分库分表之数据库分片分类
4、分库分表之策略
5、分库分表技术栈讲解-Sharding-JDBC
6、分库分表下的 ID 冲突问题与雪花算法讲解

本文章目录

  • 分库分表之实战-sharding-JDBC
    • 一、SpringBoot2.5+MybatisPlus+Sharding-Jdbc项目创建
      • 1. 在创建好的Maven项目的pom文件中添加以下pom文件依赖:
      • 2. 创建对应测试的数据库表
      • 3、创建实体类以及对应数据库实体类
    • 二、 Sharding-Jdbc常规数据源配置和水平分表
      • 配置appliaction.properties
      • ShardingSphere SQL 执行日志解析
        • 1. Logic SQL(逻辑 SQL)
        • 2. Actual SQL(实际 SQL)
        • 3. 绑定参数(实际参数值)
        • 4. 分片路由逻辑分析
    • 三、分库分表下的 ID 冲突问题解决

分库分表之实战-sharding-JDBC

一、SpringBoot2.5+MybatisPlus+Sharding-Jdbc项目创建

1. 在创建好的Maven项目的pom文件中添加以下pom文件依赖:

<properties><java.version>11</java.version><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><spring.boot.version>2.5.5</spring.boot.version><mybatisplus.boot.starter.version>3.4.0</mybatisplus.boot.starter.version><lombok.version>1.18.16</lombok.version><sharding-jdbc.version>4.1.1</sharding-jdbc.version><junit.version>4.12</junit.version><druid.version>1.1.16</druid.version><!--跳过单元测试--><skipTests>true</skipTests></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${spring.boot.version}</version><scope>test</scope></dependency><!--mybatis plus和springboot整合--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatisplus.boot.starter.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>${sharding-jdbc.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring.boot.version}</version><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin></plugins></build>

2. 创建对应测试的数据库表

  • 新建数据库ccc_shop_order_0
CREATE DATABASE `ccc_shop_order_0` 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_bin;
  • 新建数据库ccc_shop_order_1
CREATE DATABASE `ccc_shop_order_1` 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_bin;
  • 在数据库ccc_shop_order_0中新建表product_order_0、product_order_1
 use ccc_shop_order_0;CREATE TABLE `product_order_0` (`id` bigint NOT NULL AUTO_INCREMENT,`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订
单唯⼀标识',`state` varchar(11) DEFAULT NULL COMMENT 'NEW 未⽀
付订单,PAY已经⽀付订单,CANCEL超时取消订单',`create_time` datetime DEFAULT NULL COMMENT '订单⽣
成时间',`pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订
单实际⽀付价格',`nickname` varchar(64) DEFAULT NULL COMMENT '昵称',`user_id` bigint DEFAULT NULL COMMENT '⽤户id',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_bin;CREATE TABLE `product_order_1` (`id` bigint NOT NULL AUTO_INCREMENT,`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订
单唯⼀标识',`state` varchar(11) DEFAULT NULL COMMENT 'NEW 未⽀
付订单,PAY已经⽀付订单,CANCEL超时取消订单',`create_time` datetime DEFAULT NULL COMMENT '订单⽣
成时间',`pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订
单实际⽀付价格',`nickname` varchar(64) DEFAULT NULL COMMENT '昵称',`user_id` bigint DEFAULT NULL COMMENT '⽤户id',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_bin;
  • 在数据库ccc_shop_order_1中新建表product_order_0、product_order_1
use ccc_shop_order_1;CREATE TABLE `product_order_0` (`id` bigint NOT NULL AUTO_INCREMENT,`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订
单唯⼀标识',`state` varchar(11) DEFAULT NULL COMMENT 'NEW 未⽀
付订单,PAY已经⽀付订单,CANCEL超时取消订单',`create_time` datetime DEFAULT NULL COMMENT '订单⽣
成时间',`pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订
单实际⽀付价格',`nickname` varchar(64) DEFAULT NULL COMMENT '昵称',`user_id` bigint DEFAULT NULL COMMENT '⽤户id',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_bin;CREATE TABLE `product_order_1` (`id` bigint NOT NULL AUTO_INCREMENT,`out_trade_no` varchar(64) DEFAULT NULL COMMENT '订
单唯⼀标识',`state` varchar(11) DEFAULT NULL COMMENT 'NEW 未⽀
付订单,PAY已经⽀付订单,CANCEL超时取消订单',`create_time` datetime DEFAULT NULL COMMENT '订单⽣
成时间',`pay_amount` decimal(16,2) DEFAULT NULL COMMENT '订
单实际⽀付价格',`nickname` varchar(64) DEFAULT NULL COMMENT '昵称',`user_id` bigint DEFAULT NULL COMMENT '⽤户id',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_bin;

3、创建实体类以及对应数据库实体类

ProductOrderDO

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("product_order")
public class ProductOrderDO {@TableId(value = "id", type = IdType.AUTO)private Long id;private String outTradeNo;private String state;private Date createTime;private Double payAmount;private String nickname;private Long userId;
}

ProductOrderMapper

public interface ProductOrderMapper extendsBaseMapper<ProductOrderDO> {
}

目前我的工程如下,大家可以对比一下
在这里插入图片描述

二、 Sharding-Jdbc常规数据源配置和水平分表

配置appliaction.properties

spring.application.name=ccc-sharding-jdbc
server.port=8080
# 打印执⾏的数据库以及语句
spring.shardingsphere.props.sql.show=true
# 数据源 db0,如果有多个用逗号分隔,有多少个,下面具体数据库就要配置多少个
spring.shardingsphere.datasource.names=ds0,ds1
# 第⼀个数据库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://127.0.0.1:3306/ccc_shop_order_0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456# 第二个数据库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://127.0.0.1:3306/ccc_shop_order_1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456# 指定product_order表的数据分布情况,配置数据节点,⾏表达式标识符使⽤ ${...} 或 $->{...},但前者与 Spring 本身的⽂件占位符冲突,所以在 Spring 环境中建议使⽤ $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
# 指定product_order表的分⽚策略,分⽚策略包括【分⽚键和分⽚算法】
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}

这里我们使用的是mysql8.0

  1. spring.shardingsphere.datasource.ds0.password=123456 这里大家记得修改为自己数据库的密码
  2. spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://127.0.0.1:3306/ccc_shop_order_0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true 这里大家记得把ip改为自己的安排(如果数据库不在本地)

ShardingSphere SQL 执行日志解析

编写单元测试DbTest

@RunWith(SpringRunner.class)  //底层⽤junitSpringJUnit4ClassRunner
@SpringBootTest(classes = DemoApplication.class)
@Slf4j
public class DbTest {@Autowiredprivate ProductOrderMapper productOrderMapper;@Testpublic void testSaveProductOrder(){for(int i=0;i<10;i++){ProductOrderDO productOrder = new ProductOrderDO();productOrder.setCreateTime(new Date());productOrder.setNickname("ccc_i="+i);productOrder.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));productOrder.setPayAmount(100.00);productOrder.setState("PAY");productOrder.setUserId(Long.valueOf(i+""));productOrderMapper.insert(productOrder);}}
}

执行结果如下
在这里插入图片描述

我们查看控制台输出,展示了从逻辑 SQL 到实际 SQL 的路由过程。我来逐行解释:

1. Logic SQL(逻辑 SQL)
INSERT INTO product_order (out_trade_no, state, create_time, pay_amount, nickname, user_id) 
VALUES (?, ?, ?, ?, ?, ?)

这是应用程序实际执行的 SQL 语句:

  • 操作对象:product_order 表(逻辑表名)
  • 参数占位符:? 代表实际参数会在执行时传入
2. Actual SQL(实际 SQL)
ds0 ::: INSERT INTO product_order_0 (out_trade_no, state, create_time, pay_amount, nickname, user_id) 
VALUES (?, ?, ?, ?, ?, ?)

这是 ShardingSphere 根据分片规则路由后实际执行的 SQL:

  • ds0:目标数据源(数据库实例)
  • product_order_0:物理表名
  • 可以看到,逻辑表 product_order 被路由到了物理表 product_order_0
3. 绑定参数(实际参数值)
::: [d861e3e2-720a-4d16-bb67-12f96d31, PAY, 2025-06-30 16:24:23.075, 100.0, ccc_i=0, 0]

这些是占位符 ? 对应的实际参数值:

  1. out_trade_no: d861e3e2-720a-4d16-bb67-12f96d31(交易号)
  2. state: PAY(支付状态)
  3. create_time: 2025-06-30 16:24:23.075(创建时间)
  4. pay_amount: 100.0(支付金额)
  5. nickname: ccc_i=0(用户昵称)
  6. user_id: 0(用户ID,分片键)
4. 分片路由逻辑分析

根据我们之前的配置:

spring.shardingsphere.sharding.tables.product_order.table-strategy.inline.algorithm-expression=product_order_$->{user_id % 2}

user_id=0 时:

  • 0 % 2 = 0 → 路由到 product_order_0
  • 所以这条记录被写入 ds0 库的 product_order_0

三、分库分表下的 ID 冲突问题解决

在 分库分表下的 ID 冲突问题与雪花算法讲解中,我们提到了,同时我们前面的结果表明使用的时候,也确实存在ID冲突问题。因此我们需要使用雪花算法解决这个问题。

  • 方式⼀
    订单id使用MybatisPlus的配置,ProductOrder类配置@TableId(value = “id”, type = IdType.ASSIGN_ID)默认实现类为DefaultIdentifierGenerator雪花算法
    在这里插入图片描述
  • 方式⼆
    使⽤Sharding-Jdbc配置⽂件,注释DO类里面的id分配策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=idspring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE

这里我使用的是方式2,让我们再重新运行测试函数,查看结果
在这里插入图片描述

觉得有用请点赞收藏!
如果有相关问题,欢迎评论区留言讨论~

http://www.lqws.cn/news/578089.html

相关文章:

  • 【数论 拆位法】P10308 「Cfz Round 2」Osmanthus|普及+
  • 车辆工程中的压力传感技术:MEMS与薄膜传感器的实战应用
  • 从设计到开发一个小程序页面
  • Java + 阿里云 Gmsse 实现 SSL 国密通信
  • 用基础模型构建应用(第四章)AI Engineering: Building Applications with Foundation Models学习笔记
  • Springboot + vue + uni-app小程序web端全套家具商场
  • MongoDB 安装使用教程
  • 第81题:搜索旋转排序数组Ⅱ
  • 【软考高项论文】论信息系统项目的干系人管理
  • 百度文库智能PPT月访问量超3400万,用户规模翻倍增长
  • 中钧科技亮相2025 亚欧商品贸易博览会,赋能数字经济新未来!
  • pyspark driver 上传pod本地文件到对象存储
  • AWS 开源 Strands Agents SDK,简化 AI 代理开发流程
  • Hive SQL 实战:电商销售数据分析全流程案例
  • Git远程仓库迁移与分支关联技术分享
  • 【Python使用】嘿马python运维开发全体系教程第2篇:日志管理,Linux概述【附代码文档】
  • 【硬核数学 · LLM篇】3.1 Transformer之心:自注意力机制的线性代数解构《从零构建机器学习、深度学习到LLM的数学认知》
  • Android Compose Modifier 详细解析
  • K8s-Pod深度解析
  • 鸿蒙进阶——Mindspore Lite AI框架源码解读之模型加载详解(五)
  • 阶段二开始-第一章—8天Python从入门到精通【itheima】-121节+122节(函数和方法的类型注解+Union联合类型注解)
  • Ruby 安装使用教程
  • 单例模式7种实现
  • Golang的多环境配置
  • Golang快速开发框架——项目立项与系统配置读取组件viper(一)
  • uni-app使用uview2自定义tabber
  • camera调试:安卓添加xml注册
  • 【软考高项论文】论信息系统项目的整体管理
  • Java 图书管理系统
  • 使用Verilog设计模块输出中位数,尽可能较少资源使用