开发一个简单的数据库路由进行分库分表

今天我们来看看一个简单的数据库路由组件要怎么开发出来,这篇文章分为几个步骤进行介绍,分别为:

  1. 什么是数据库路由
    1. 路由组件的作用
    2. 为什么要自研组件
    3. 需要用到什么技术
  2. 整体的业务流程
  3. 主要代码

介绍

数据库路由的作用

使用数据库路由是在业务体量很大, 数据量增长过快,所以要把用户的数据拆分到不同的库表中,以此来减轻单机的压力。

数据库路由是用于分库分表操作,有两种方式。
1)垂直拆分
根据业务分类,将不同的业务表分布在不同的数据库中。可以将数据的压力分担到不同的数据库中,专库专用。
2)水平拆分
当垂直拆分遇到单机瓶颈的时候,就可以将一张数据表拆分多张表,放在不同的数据库中。

本篇文章也是基于水平拆分进行讲解。

为什么要自研数据库路由?

明明有一些成熟的路由组件,为什么还要自研?

1、更容易维护; 市面上有路由组件,比如:shardingsphere;但是这个组件非常庞大,而且我们也需要随着组件的版本给项目升级。而自研组件,维护起来就更容易。

2、更容易扩展; 我们可以结合自身的业务需求,去对组件进行一系列的扩展。比如说自定义路由协议、扫描指定的库表数据等等。

3、更安全; 自研的组件不会有因为额外导入Jar包,导致项目出现问题的风险。

最后是否去自研一个路由组件或者使用已经非常成熟的路由组件,还是要根据自己项目的业务需求来决定。我们可以为了更加的匹配项目,去自己研发一个简单的路由组件。也可以去使用成熟的组件,都可以。

需要什么技术?

开发一个简单的路由组件并不需要有多么🐮的技术框架,你需要了解的是关于SpringBoot的starter开发、面向切面编程、散列算法、Mybatis拦截器以及Java反射。

用到的技术都是比较基础的, 在学习这个路由组件开发的过程,你也能够务实好自身的基础。

整体流程

上面简单的介绍了一下什么是数据库路由,接下来我们来看看这个组件整体的一个流程是什么。首先我们要用到SpringBoot的starter开发,就是在项目启动的时候,去进行一系列的数据库的初始化配置。然后要用到AOP面向切面,自定义一个路由注解配置在你想要进行分库分表的接口方法处。当使用这个方法的时候,就会通过AOP定义库表索引。当连接数据库的使用getConnection()的时候,就会根据库表索引去切换数据源。最后,实现Mybatis的拦截器,通过反射修改SQL语句的表名,至此就完成了整体的流程。如下图:

在这里插入图片描述

主要代码介绍

代码有很多,我们主要介绍一下切换数据源的代码以及通过散列设置库表索引的方法。

1)数据源切换

@Bean
public DataSource dataSource(){Map<Object,Object> targetDatasource = new HashMap<>();for (String key : dataSourceMap.keySet()) {Map<String, Object> map = dataSourceMap.get(key);targetDatasource.put(key,new DriverManagerDataSource(map.get("url")+"",map.get("username")+"",map.get("password")+""));}DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDatasource);dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);return dynamicDataSource;
}

数据源切换的代码就这么简单,看到这你应该也不知道到底是如何切换的。其实归根结底是因为DynamicDataSource 继承了AbstractRoutingDataSource,进去看这个源码后我们在getConnection()中能够发现一点端倪。
在这里插入图片描述
在getConnection()之前,先去确定了一个目标数据源,再让我们去看看determineTargetDataSource的代码。
在这里插入图片描述
看到了吗,数据源默认使用的是resolvedDataSources里面的,如果没有再使用默认的数据源。在上面我们切换数据源的代码可以看到,我们是有设置了一个targetDataSource的,但是和resolvedDataSources又有什么关系?
在这里插入图片描述
看这个代码就知道了。看到这,不知道你对数据源的切换是否了解了呢?

2)散列算法
看完了数据源的切换,我们接下来看看是怎么设置库表索引的。我们都知道,如果单纯的在Map中设置索引的话,就很有可能会出现哈希碰撞,我们可以参考HashMap的方法,使用扰动函数让数据更加分散。

int size = tbCount + dbCount;
String key = "申未曲"
int idx = (size - 1) & (key.hashCode() ^ key.hashCode() >>> 16);
int dbIdx = idx / tbCount + 1;
int tbIdx = idx - tbCount * (dbIdx + 1);

这样我们就可以在size的范围内去获取到对应的索引了。

我们来理解一下代码,先看看第三行。

int idx = (size - 1) & (key.hashCode() ^ key.hashCode() >>> 16);

这句代码分为了两个部分,第一个部分是将两个key的哈希值的前后16为进行了按位异或。比如说“申未曲”的二进制码为:1110001001101100101111011,不足32为前补0,得到了:
00000001110001001101100101111011 将这个二进制码右移16位就得到了:
00000000000000000000000111000100 按位异或之后就得到了如下二进制:
00000001110001001101100111111111 = 29678079

假设size=10,那么接下来就需要让size与hashcode进行按位与,29678079 & 9
00000001110001001101100111111111 & 00000000000000000000000000001001得到的值为1001=9

int dbIdx = idx / tbCount + 1;
int tbIdx = idx - tbCount * (dbIdx + 1);

然后再看看这两句代码,这样看可能也不好理解,那我们举个例子。当前有8张表,分别放在了两个库内,获取到的索引分别为1~8,那当索引idx=5的时候,所在的是第几个库第几张表?

带入进来,5 / 4 + 1 = 2 (库) ;5 - 4 * (2 -1 ) 1 (表),认真理解后还是很简单的。

就说这些, 大家可以根据上面提供的流程与逻辑,看看能不能自己研发一个出来。代码结构图如下:
在这里插入图片描述

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

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

相关文章

产品解读|有了JMeter,为什么还需要MeterSphere?

提起JMeter&#xff0c;相信大部分的测试人员应该都很熟悉。JMeter因其小巧轻量、开源&#xff0c;加上支持多种协议的接口和性能测试&#xff0c;在测试领域拥有广泛的用户群体。一方面&#xff0c;测试人员会将其安装在个人的PC上&#xff0c;用以满足日常测试工作的需要&…

【SpringCloud Alibaba】(一)微服务介绍

此专栏内容皆来自于【冰河】的《SpringCloud Alibaba 实战》文档。 1. 专栏介绍 我们先来看看《SpringCloud Alibaba实战》专栏的整体结构吧&#xff0c;先上图 从上图&#xff0c;大家可以看到&#xff0c;专栏从整体上分为十个大的篇章&#xff0c;分别为 专栏设计、微服务…

【Git】

学习来自于&#xff1a; 女朋友乱用Git&#xff0c;差点把我代码删了。。。 一些常用的Git 知识点整理 关于Git这一篇就够了 Git基本命令大全 30分钟精通Git&#xff0c;学不会来找我 Git 版本管理 | 莫烦PYTHON Git 代码版本管理教程 文章目录 【前言】集中式与分布式的…

Jmeter配置起来太繁琐?试试RunnerGo

在用jmeter做性能测试时想看完整一点的测试报告&#xff0c;想配置阶梯模式来压测&#xff0c;想配置不同的接口并发这些都需要安装插件并且影响机器性能&#xff0c;想做自动化测试还得放到jenkins&#xff0c;这些配置起来太繁琐。今天给大家推荐一款测试平台RunnerGo&#x…

【Redis】高级篇: 一篇文章讲清楚Redis的单线程和多线程

目录 面试题 Redis到底是多线程还是单线程&#xff1f; 简单回答 详解 Redis的“单线程” Redis为什么选择单线程&#xff1f; 后来Redis为什么又逐渐加入了多线程特性&#xff1f; Redis为什么快&#xff1f; 回答 IO多路复用 Unix网络编程的5种IO模型 主线程和IO…

【100天精通python】Day9:数据结构_字典、集合

目录 目录 1 字典 1.1 字典的基本操作示例 1.2 字典推导式 2 集合 2.1 集合的常用操作示例 3 列表、元组、字典、集合的区别 1 字典 在Python中&#xff0c;字典&#xff08;Dictionary&#xff09;是一种无序的数据结构&#xff0c;用于存储键值对的集合。每个…

华为openGauss数据库入门 - gsql用法

目录 1.1 gsql的语法 1.2 gsql常用选项 1.2.1 最常用的必要选项 1.2.2 -r选项 1.2.3 -E选项 1.2.4 -t选项 1.2.5 -A选项 1.2.6 -v选项 1.2.7 -c选项 1.2.8 -f选项 1.2.9 -q选项 1.3 gsql的元命令 1.3.1 \l命令 1.3.2 \du命令和\dg命令 1.3.3 \db命令 1.3.4 \d…

微服务——Nacos配置管理

目录 Nacos配置管理——实现配置管理 配置管理实践 Nacos配置管理——微服务配置拉取 Nacos配置管理——配置热更新 方式一: ​编辑 方式二(推荐方式): Nacos配置管理——多环境配置共享 优先级问题 Nacos配置管理——nacos集群搭建 总结​编辑 Nacos配置管理——实现配置管…

物联网的通信协议

物联网的通信协议 目录 物联网的通信协议一、UART串口通信1.1 串口通信1.2 异步收发1.3 波特率1.4 串口通信协议的数据帧1.5 优缺点1.5.1 优点1.5.2 缺点 二、I^2^C2.1 I^2^C2.2 I^2^C2.3 数据有效性2.4 起始条件S和停止条件P2.5 数据格式2.6 协议数据单元PDU2.7 优缺点2.7.1 优…

(五)RabbitMQ-进阶 死信队列、延迟队列、防丢失机制

Lison <dreamlison163.com>, v1.0.0, 2023.06.23 RabbitMQ-进阶 死信队列、延迟队列、防丢失机制 文章目录 RabbitMQ-进阶 死信队列、延迟队列、防丢失机制死信队列延迟队列延迟队列介绍**延迟队列_死信队列_的实现**延迟队列_插件实现下载插件RabbitMQ 配置类RabbitMQ …

实现PC端微信扫码native支付功能

目录 实现PC端微信扫码 简介 实现步骤 1. 获取商户号 2. 生成支付二维码 3. 监听支付结果 4. 发起支付请求 5. 处理支付回调 示例代码 结论 Native支付 Native支付的工作原理 Native支付的优势 Native支付的应用和市场地位 开通使用微信 native 支付流程 步骤一…

Oracle输出文本平面(CSV、XML)文本数据详细过程

此过程是提供给前端,调用的接口,为报表提供”下载“功能。以下是本人在测试环境的测试,有什么不足的地方,请留言指教,谢谢。 1、测试表 分别对测试表输出csv、xml两种格式文件数据。前期的准备工作。 --在服务器端创建directory,用管理员用户 create or replace directo…

ftp传文件越来越慢的原因,以及解决方案

FTP 是一种常用的文件传输协议&#xff0c;它基于客户端-服务端模型工作&#xff0c;允许用户通过网络传输文件。但是&#xff0c;有时候在使用 FTP 的过程中&#xff0c;文件传输速度会逐渐变慢&#xff0c;这给用户带来了很多困扰。本文将分析 FTP 传文件变慢的原因&#xff…

QT DAY2

1.思维导图 2.继续完善登录框&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;跳转到新的界面中 Second.h #ifndef SECOND_H #define SECOND_H#include <QWidget> #include <QtCore/QDebug> #include <QIcon> #include <QPushButton> …

当ChatGPT应用在汽车行业,具体有哪些场景?

​ ChatGPT有潜力彻底改变汽车行业并将其提升到新的高度。在ChatGPT的加持下&#xff0c;该行业的多个领域都将取得重大变化。 利用ChatGPT作更高级的虚拟助理 你可能用过现有的虚拟助理&#xff0c;它们一系列的回复有时候让人不得不感叹一句“人工智障”&#xff01;然而&a…

2023-07-26 LeetCode每日一题(更新数组后处理求和查询)

2023-07-26每日一题 一、题目编号 2569. 更新数组后处理求和查询二、题目链接 点击跳转到题目位置 三、题目描述 给你两个下标从 0 开始的数组 nums1 和 nums2 &#xff0c;和一个二维数组 queries 表示一些操作。总共有 3 种类型的操作&#xff1a; 操作类型 1 为 querie…

跨境电商多语言带直播功能功能列表

一、直播导购 1.直播入驻管理&#xff1a;直播入驻实际上就是商家入驻&#xff0c;开通商家后会获得直播权限 2.直播观看/拉流页面(分三屏&#xff0c;可以左右滑动&#xff09;&#xff1a; 左屏&#xff1a; 直播间信息&#xff1a;直播间名称、直播封面、房间号、在线人数、…

【C语言项目】扫雷(详解,附图、附代码示范)

文章目录 项目思路一、分文件进行创建二、进入游戏前的目录2.1 目录的功能&#xff1a;2.2 目录界面&#xff1a;2.3 选择进入或退出游戏2.3.1 代码示范2.3.2 图片示例&#xff1a; 三、画出游戏界面3.1 创建两个数组3.2 初始化数组3.3 打印游戏界面3.3.1 代码思路3.3.2 代码示…

gin框架内容(二)

上一篇过于gin的内容 https://mp.csdn.net/mp_blog/creation/editor/131953861 CSDNhttps://mp.csdn.net/mp_blog/creation/editor/131953861 一、路由组 为了管理具有相同前缀的URL, 将拥有URL共同前缀的路由划分为一组 为了代码的阅读性&#xff0c;使用{}包裹相同组的路由…

WPF icon的设置

想给控件设置个圆形图片&#xff0c;代码如下&#xff1a; ​<Setter Property"Icon"><Setter.Value><Image Source"/WpfApp1;component/Resource/1.ico" Width"16" Height"16"/></Setter.Value></Setter&…