互联网三高-数据库高并发之分库分表ShardingJDBC

1 ShardingJDBC介绍

        1.1 常见概念术语

                ① 数据节点Node:数据分片的最小单元,由数据源名称和数据表组成

                        如:ds0.product_order_0

                ② 真实表:再分片的数据库中真实存在的物理表

                        如:product_order_0

                ③ 逻辑表:相同逻辑和数据结构表的总称

                        如:product_order

                ④ 绑定规则:指分片规则一致的主表和子表

                        如:order表和order_item表,都是按照order_id分片

                绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率提升

        1.2 常见分片算法

                分片键:用于分片的数据库字段,是将数据库(表)水平拆分的关键字段

                ShardingJDBC既支持单分片键,也支持多个字段进行分片

                分片策略

                

                        ① 行表达式分片:InlineShardingStrategy

                                只支持单分片键

                                使用groovy表达式,提供对SQL语言的 = 和 IN 的分片操作支持

                                如:product_order_$->{user_id % 2} => product_order_0 和 product_order_1

                        ② 标准分片:StandardShardingStrategy

                                只支持单分片键

                                PreciseShardingAlgorithm:精准分片,处理 = 和 IN 的分片操作

                                RangeShardingAlgorithm:范围分片,处理 BETWEEN AND 的分片操作

                        ③ 复合分片:ComplexShardingStrategy

                                支持多分片键

                                提供  = 、 IN 和 BETWEEN AND 的分片操作

                        ④ Hint分片:HintShardingStrategy

                                无需配置分片键,外部手动指定分片键

                        ⑤ 不分片:NoneShardingStrategy

2 快速入门

        SpringBoot整合ShardingJDBC

(1)导入依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.5.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.5.5</version></dependency>
</dependencies>

(2)编写启动类

@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.pandy.mapper")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}

(3)创建数据库、表(2个库,4个表)

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;

(4)编写实体类

@Data
@TableName("product_order")
@EqualsAndHashCode(callSuper = false)
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;
}

(5)编写配置信息-分库分表(这里以分表为例,以user_id为分片键)

# 打印执行的数据库以及语句
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.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://192.168.5.135:3306/sharding_db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=root# 第二个数据库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://192.168.5.135:3306/sharding_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=root# 指定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}

(6)单元测试

@Test
public void testInsertProductOrder() {for(int i=0; i<10; i++) {ProductOrderDO orderDO = new ProductOrderDO();orderDO.setOutTradeNo(UUID.randomUUID().toString().replaceAll("-",""));orderDO.setCreateTime(new Date());orderDO.setPayAmount(100d);orderDO.setState("NEW");orderDO.setNickname("pandy-" + i);orderDO.setUserId(Long.parseLong(i + ""));productOrderMapper.insert(orderDO);}
}

分库分表执行逻辑

(7)主键重复问题

        使用自增主键,出现主键ID重复问题

3 分库分表常见主键ID生成策略

        需求:

                ① 性能强劲

                ② 全局唯一

                ③ 防止恶意用户根据ID规则来猜测和获取数据

        3.1 业界常见解决方案

                (1)自增ID,设置不同的自增步长

                        缺点:① 未来扩容比较麻烦

                                ② 主从切换时不一致可能会导致重复ID

                                ③ 性能瓶颈

                (2)UUID

UUID.randomUUID().toString().replaceAll("-","");

                        优点:性能非常高,没有网络消耗

                        缺点:① 无序的字符串,不具备趋势自增特性

                                ② UUID太长,不易于存储,浪费存储空间

                (3)Redis发号器

                        利用Redis的incr 或incrby 来实现,原子操作,线程安全

                        缺点:① 需要占用网络资源,增加系统复杂性

                (4)snowflake雪花算法

                        twitter开源的分布式ID生成算法

                        生成的ID中包含时间戳,所以生成的ID按照时间递增

                        部署多台服务器,需要保证系统时间一样,机器编号不一样

                        缺点:依赖系统时间(时钟回拨问题)

                配置使用shardingjdbc的雪花算法

# 配置ID使用雪花算法
spring.shardingsphere.sharding.key-generator.column=id
spring.shardingsphere.sharding.key-generator.type=SNOWFLAKE

        看一下源码, shardingjdbc的雪花算法是怎么解决时钟回拨问题的?

4 广播表和绑定表配置 

        广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致

                如:字典表,配置表等

(1)创建一个配置表

CREATE TABLE `config` (`id` bigint unsigned NOT NULL COMMENT '主键id',`config_key` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '配置key',`config_value` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '配置value',`type` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '类型',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

(3)创建实体类

@Data
@TableName("config")
@EqualsAndHashCode(callSuper = false)
public class ConfigDO {@TableId(value = "id")private Long id;private String configKey;private String configValue;private String type;
}

(3)添加广播表配置

#配置广播表
spring.shardingsphere.sharding.broadcast-tables=config

(4)测试代码 

@Test
public void insertConfig() {ConfigDO configDO = new ConfigDO();configDO.setConfigKey("iphone");configDO.setConfigValue("iphone16秒杀广告");configDO.setType("AD");configMapper.insert(configDO);
}

5 分库分表核心流程

        解析 --> 路由 --> 改写 --> 执行 --> 结果归并

        (1)解析

                词法解析

                语法解析

        (2)路由

                分片路由(带分片键):直接路由,标准路由,笛卡尔积路由

                广播路由(不带分片键):全库表路由,全库路由,全实例路由

        (3)改写

                将逻辑SQL改写为可以正确执行的真实SQL

        (4)执行

                采用自动化的执行引擎

                内存限制模式:适用于OLAP(连接数量不做限制,多线程并发执行)

                连接限制模式:适用于OLAP(1库1线程,多库多线程,保证数据库资源足够多使用)

        (5)结果归并

                从各个数据节点获取多数据结果集,组合成为一个结果集

                流式归并:每一次从结果集中获取到数据

                内存归并:分片结果集的数据存储在内存中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/76734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BM25、BGE以及text2vec-base-chinese的区别

BM25、BGE以及text2vec-base-chinese的区别 BM25 原理:BM25(Best Matching 25)是一种基于概率检索模型的算法,它通过考虑查询词与文档之间的匹配程度、文档的长度等因素,来计算文档对于查询的相关性得分。具体来说,它会给包含查询词次数较多、文档长度适中的文档更高的分…

Python中try用法、内置异常类型与自定义异常类型拓展

目录 try介绍与语法格式try具体使用案例except的异常类型简介案例内置的常见异常类型自定义异常类型继承关系用途 注意事项 try介绍与语法格式 在 Python 里&#xff0c;try 语句主要用于异常处理&#xff0c;其作用是捕获并处理代码运行期间可能出现的异常&#xff0c;避免程…

【第41节】windows的中断与异常及异常处理方式

目录 一、中断与异常处理 1.1 中断与异常 1.2 IDT 1.3 异常的概念 1.4 异常分类 二、windows异常处理方式 2.1 概述 2.2 结构化异常处理 2.3 向量化异常处理之VEH 2.4 向量化异常处理之VCH 2.5 默认的异常处理函数 2.6 如何手动安装 SEH 节点 2.7 异常处理的优先级…

分布式日志治理:Log4j2自定义Appender写日志到RocketMQ

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

【HTML】html文件

HTML文件全解析&#xff1a;搭建网页的基石 在互联网的广袤世界里&#xff0c;每一个绚丽多彩、功能各异的网页背后&#xff0c;都离不开HTML文件的默默支撑。HTML&#xff0c;即超文本标记语言&#xff08;HyperText Markup Language&#xff09;&#xff0c;作为网页创建的基…

oracle命令上下左右键无法使用如何解决?

1、问题如图 2、解决办法 (1) 安装readline yum -y install readline* &#xff08;2&#xff09;安装 rlwrap ##下载 wget http://files.cnblogs.com/files/killkill/rlwrap-0.30.tar.gz.zip ##解压 tar -xzvf rlwrap-0.30.tar.gz.zip ##编译安装 ./configure make &&…

vue事假机制都有哪些

Vue 的事件机制主要包含以下几种类型和方式&#xff0c;可以分为组件内部事件、父子组件通信事件、原生 DOM 事件封装、修饰符增强等&#xff0c;下面详细分类介绍&#xff1a; 一、DOM 事件绑定&#xff08;最基础的事件&#xff09; 使用 v-on&#xff08;或简写 &#xff0…

系统编程2(消息队列)

⦁ 消息队列概念 Linux系统中消息队列&#xff08;Message Queue&#xff09;是进程间通信的一种方式&#xff0c;这种通信机制的好处是可以传输指定类型(用户可以自行定义)的数据&#xff0c;相同类型的数据根据到达顺序在队列中进行排队。 当然&#xff0c;不同类型的数据不…

Pytorch深度学习框架60天进阶学习计划 - 第41天:生成对抗网络进阶(二)

Pytorch深度学习框架60天进阶学习计划 - 第41天&#xff1a;生成对抗网络进阶&#xff08;二&#xff09; 7. 实现条件WGAN-GP # 训练条件WGAN-GP def train_conditional_wgan_gp():# 用于记录损失d_losses []g_losses []# 用于记录生成样本的多样性&#xff08;通过类别分…

python 微博爬虫 01

起因&#xff0c; 目的: ✅下载单个视频&#xff0c;完成。✅ 获取某用户的视频列表&#xff0c;完成。剩下的就是&#xff0c; 根据视频列表&#xff0c;逐个下载视频&#xff0c;我没做&#xff0c;没意思。获取视频的评论&#xff0c;以后再说。 关键点记录: 1. 对一个视…

Servlet、HTTP与Spring Boot Web全面解析与整合指南

目录 第一部分&#xff1a;HTTP协议与Servlet基础 1. HTTP协议核心知识 2. Servlet核心机制 第二部分&#xff1a;Spring Boot Web深度整合 1. Spring Boot Web架构 2. 创建Spring Boot Web应用 3. 控制器开发实践 4. 请求与响应处理 第三部分&#xff1a;高级特性与最…

vue中根据html动态渲染内容2.0

上次使用的是p标签用的contenteditable代替的可编辑的input&#xff0c;最后实现还是选择了用el-input的textarea方式。 一开始考虑的是需要根据用户输入自动撑开输入框&#xff0c;所以选择了p标签可编辑。 最后发现还是el-input会更好一点&#xff0c;只不过需要处理输入框撑…

CentOS 系统磁盘扩容并挂载到根目录(/)的详细步骤

在使用 CentOS 系统时&#xff0c;经常会遇到需要扩展磁盘空间的情况。例如&#xff0c;当虚拟机的磁盘空间不足时&#xff0c;可以通过增加磁盘容量并将其挂载到根目录&#xff08;/&#xff09;来解决。以下是一个完整的操作流程&#xff0c;详细介绍了如何将新增的 10G 磁盘…

LINUX基础 [二] - Linux常见指令

目录 &#x1f4bb;前言 &#x1f4bb;指令 &#x1f3ae;ls指令 &#x1f3ae;pwd指令 &#x1f3ae;whoami指令 &#x1f3ae;cd指令 &#x1f3ae;clear指令 &#x1f3ae;touch指令 &#x1f3ae;mkdir指令 &#x1f3ae;rmdir指令 &#x1f3ae;rm指令 &#…

基于php的成绩分析和预警与预测网站(源码+lw+部署文档+讲解),源码可白嫖!

摘要 人类现已迈入二十一世纪&#xff0c;科学技术日新月异&#xff0c;经济、资讯等各方面都有了非常大的进步&#xff0c;尤其是资讯与网络技术的飞速发展&#xff0c;对政治、经济、军事、文化、教育等各方面都有了极大的影响。 利用电脑网络的这些便利&#xff0c;发展一套…

《从底层逻辑剖析:分布式软总线与传统计算机硬件总线的深度对话》

在科技飞速发展的当下&#xff0c;我们正见证着计算机技术领域的深刻变革。计算机总线作为信息传输的关键枢纽&#xff0c;其发展历程承载着技术演进的脉络。从传统计算机硬件总线到如今备受瞩目的分布式软总线&#xff0c;每一次的变革都为计算机系统性能与应用拓展带来了质的…

Spring Boot 3.5新特性解析:自动配置再升级,微服务开发更高效

&#x1f4dd; 摘要 Spring Boot 3.5作为Spring生态的最新版本&#xff0c;带来了多项令人振奋的改进。本文将深入解析其中最核心的自动配置增强特性&#xff0c;以及它们如何显著提升微服务开发效率。通过详细的代码示例和通俗易懂的讲解&#xff0c;您将全面了解这些新特性在…

【前端】webpack一本通

今日更新完毕&#xff0c;不定期补充&#xff0c;建议关注收藏点赞。 目录 简介Loader和Plugin的不同&#xff1f;&#xff08;必会&#xff09; 使用webpack默认只能处理js文件 ->引入加载器对JS语法降级&#xff0c;兼容低版本语法合并文件再次打包进阶 工作原理Webpack 的…

leetcode 264. Ugly Number II

动态规划解决。 关键是理解如何生成新的丑数。这道题和经典的斐波那契数列问题其实是一样的。求第n个数&#xff0c;需要用第n个数前面的数来求。不同的是&#xff0c;斐波那契数列不会重复。而本题的丑数&#xff0c;会重复出现。 class Solution { public:int nthUglyNumbe…

深入理解 HTML5 语义元素:提升网页结构与可访问性

引言 在构建网页的过程中&#xff0c;合理的结构与清晰的语义对于网页的质量、可维护性以及搜索引擎优化&#xff08;SEO&#xff09;都至关重要。HTML5 引入了一系列语义元素&#xff0c;为开发者提供了更精准描述网页内容的工具。本文将深入探讨 HTML5 语义元素的作用、使用…