使用ShardingSphere实现MySql的分库分表

目录

 

一 什么是ShardingSphere分库分表

二 代码实现

1.导入相关依赖

2.配置相关参数

3.创建学生类以及mapper接口

4.实现 StandardShardingAlgorithm接口自定义分片算法


唐洋洋我知道你在看!!!嘿嘿

一 什么是ShardingSphere分库分表

我们平时在设计数据库的时候,一般都是一个数据库里面有很多张表,比如用户表,那么所有的用户信息都会存在这一张表里面。但是当数据量特别大的时候,如果你只用一个数据库一张用户表来存,这样就会到这这个数据库访问压力过大。所以分库分表就是,把大量用户数据分成多个数据库的多张表来存,这里以学生信息表为例:

7d2906c055de41f2a0f46dfda76f13d9.png

可以看到,我创建了两个数据库,每个数据库分别有两张表来存储学生信息,这样相当于一共有四张学生表了,这样就能减少每个数据库的访问压力。

既然分库分表的意思明白了,那么我们查询或者插入学生表的时候,该怎么操作呢?比如我现在要存入一个学生信息,我该往哪个表存呢?那么这里肯定是通过计算出来的,而且是某种算法,整体要平均。

所以这就是我们ShardingSphere的作用。

二 代码实现

1.导入相关依赖


        <!--        shardingsphere依赖-->


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</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>shardingsphere-jdbc-core</artifactId>
            <version>5.3.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>snakeyaml</artifactId>
                    <groupId>org.yaml</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 坑爹的版本冲突 -->
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.26</version>
        </dependency>

2.配置相关参数

application.yml参数:

9429aac9efec43a8956ac969f89f2fec.png

spring:
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:shardingsphere-config.yaml

 shardingsphere-config.yaml参数:

72bef31d8ce2452a836b92fe6b4c3ae4.png

dataSources:
  student_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/student_0?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: 1234
  student_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/student_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: 1234
rules:
  - !SHARDING #分片规则
    tables:
      tb_student: #逻辑表名
        actualDataNodes: student_${0..1}.t_student_${0..3}
        databaseStrategy: # 分库策略
          standard: # 用于单分片键的标准分片场景
            shardingColumn: id # 分片列名称
            shardingAlgorithmName:  db_hash_mode_algorithm # 分片算法名称
        tableStrategy: # 分表策略,同分库策略
          standard: # 用于单分片键的标准分片场景
            shardingColumn: id # 分片列名称
            shardingAlgorithmName:  tb_student_hash_mode_algorithm # 分片算法名称
    # 分片算法配置
    shardingAlgorithms:
      db_hash_mode_algorithm:
        type: CLASS_BASED  # 分片算法类型  自定义
        props: # 分片算法属性配置
          db_sharding-count: 2
          table_sharding-count: 4
          strategy: standard #标准的分片算法
          algorithmClassName: com.feisi.shardingsphere.MyStandardShardingAlgorithm
      tb_student_hash_mode_algorithm:
        type: HASH_MOD
        props:
          sharding-count: 4
props:
  sql-show: true

3.创建学生类以及mapper接口

492f3f78e4db48d5a9d0877e092aa5e0.png

学生类:

package com.feisi.shardingsphere.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@TableName("tb_student")
@Builder
@Component
public class Student {
    @TableId(type = IdType.INPUT)
    private Long id;  //分片键
    private String name;
    private Integer age;
}

学生mapper接口:

package com.feisi.shardingsphere.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.feisi.shardingsphere.pojo.Student;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface StudentMapper extends BaseMapper<Student> {
}

4.实现 StandardShardingAlgorithm接口自定义分片算法

package com.feisi.shardingsphere;

import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.sharding.algorithm.sharding.ShardingAutoTableAlgorithmUtil;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.apache.shardingsphere.sharding.exception.algorithm.sharding.ShardingAlgorithmInitializationException;

import java.util.Collection;
import java.util.Optional;
import java.util.Properties;

public class MyStandardShardingAlgorithm implements StandardShardingAlgorithm<Comparable<?>> {


    // 数据库的数量配置参数名
    private static final String DB_SHARDING_COUNT_KEY = "db_sharding-count";
    // 表的数量配置参数名
    private static final String TABLE_SHARDING_COUNT_KEY = "table_sharding-count";
    private int dbShardingCount;
    private int tableShardingCount;

    @Override
    public void init(final Properties props) {
        dbShardingCount = getDbShardingCount(props);
        tableShardingCount = getTableShardingCount(props);
    }

    private int getTableShardingCount(Properties props) {
        ShardingSpherePreconditions.checkState(props.containsKey(TABLE_SHARDING_COUNT_KEY), () -> new ShardingAlgorithmInitializationException(getType(), "Sharding count cannot be null."));
        return Integer.parseInt(props.getProperty(TABLE_SHARDING_COUNT_KEY));
    }

    private int getDbShardingCount(Properties props) {
        ShardingSpherePreconditions.checkState(props.containsKey(DB_SHARDING_COUNT_KEY), () -> new ShardingAlgorithmInitializationException(getType(), "Sharding count cannot be null."));
        return Integer.parseInt(props.getProperty(DB_SHARDING_COUNT_KEY));
    }


    @Override
    //availableTargetNames: ds_${0..1}: ds_0  ds_1
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Comparable<?>> shardingValue) {
        //id进行hash    数据库数量 2   表的数量 4
//        这里使用哈希取余的算法
        // hash % 4 = 0..3 /2   0,1 /2 = 0   2,3/2 = 1
        String suffix = String.valueOf(hashShardingValue(shardingValue.getValue()) % tableShardingCount / dbShardingCount);
        return ShardingAutoTableAlgorithmUtil.findMatchedTargetName(availableTargetNames, suffix, shardingValue.getDataNodeInfo()).orElse(null);
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Comparable<?>> shardingValue) {
        return availableTargetNames;
    }
    //对分片键的值进行hash算法
    private long hashShardingValue(final Object shardingValue) {

        return Math.abs((long) shardingValue.hashCode());
    }

    @Override
    public String getType() {
        return "CLASS_BASED";
    }

}

这里自定义分片算法在dosharding方法里面,分片算法的意思就是,根据你的分片建通过算法确定你的学生信息存储到哪个数据库中的哪张表里面去。

这里使用的是哈希取余算法,先根据你的分片键(这里的分片键就是id),计算出它的哈希值,然后:

        哈希值%你的数据表的数量=要存的哪块表

        要存的哪块表%你的数据库的数量=要存在哪个库里面。

为什么公式是这样的,因为我们的每个库从0开始,每个库对应下面的表也是从0开始。所以这个公式就能算出来。

比如一个id的哈希值是:448488114

我们的库数量是2个(0,1)

表数量是4个(0,1,2,3)

那么:448488114%4=2(存在表2里面)

但是表2在数据库1下面,所以你的算法不能算错,如果算到0库,那么就找不到这个张表了。

2/2=1(数据库1)

这样就完成了,最后算到你这个学生信息应该存到数据库1下面的数据表2中。

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于UDP的简易网络通信程序

目录 0.前言 1.前置知识 网络通信的大致流程 IP地址 端口号&#xff08;port&#xff09; 客户端如何得知服务器端的IP地址和端口号&#xff1f; 服务器端如何得知客户端的IP地址和端口号&#xff1f; 2.实现代码 代码模块的设计 服务器端代码 成员说明 成员实现 U…

2024 年 GitLab Global DevSecOps 报告解读

近日 GitLab 正式发布了 2024 年 GitLab Global DevSecOps 报告&#xff0c;报告主题为 What’s next in DevSecOps。在全球有超 5000 位 IT 人员参与了该报告的调研&#xff0c;超 70% 为企业管理者&#xff0c;50% 以上的受访者所在企业规模超过 500人。该报告深刻揭示了在 A…

Andrej Karpathy谈AI未来:自动驾驶、Transformer与人机融合

引言 在人工智能领域&#xff0c;Andrej Karpathy 是一个无法忽视的名字。从他早期在 OpenAI 的工作&#xff0c;到后来担任 Tesla 的 AI 主管&#xff0c;他在自动驾驶、深度学习等方面的贡献广为人知。最近&#xff0c;卡帕西做客了著名的播客节目 No Priors&#xff0c;他在…

鸿蒙开发基础

页面跳转 了解代码初始结构 /*** 装饰器&#xff1a;用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。* Entry&#xff1a;表示该自定义组件为入口组件 * Component&#xff1a;表示自定义组件* State&#xff1a;表示组件中的状态变量&#xff0c;状态变量变…

hh exe所选的程序不能与此文件类型相关联。请选择其他程序。

按照hh exe打开chm文件显示所选的程序不能与此文件类型相关联。请选择其他程序。 以上错误来自于 cmd命令行 cd C:\Windows\hh.exe 要打开的chm文件报错 其实根本原因是在设置中.chm文件默认打开方法被其他软件占用了&#xff0c;解决办法只能删除那个软件&#xff0c;如果是W…

接口测试(十二)

一、前台、后台、数据库三者关系 fiddler抓包是抓取客户端 --> 服务端 发送的的请求接口 开N个网页&#xff0c;只要有对后端发送请求&#xff0c; fiddler是无差别抓取 F12只抓取当前页面的数据 二、接口概念 接口是什么&#xff1f;— 传递数据的通道 测试系统组件间接口…

五、(JS)window中的定时器

一、为什么叫做window中的定时器 我们在全局中会用到一些函数&#xff0c;比如说alert函数&#xff0c;prompt函数&#xff0c;setTimeout等等 我们有在这里定义过这些函数吗&#xff1f;很明显没有。可见我们这些函数都是来自于window。 所以还可以写成window.setTimeout。…

AtCoder Beginner Contest 371

A - Jiro &#xff1a; 题目&#xff1a; 代码&#xff1a; #include <bits/stdc.h>using namespace std;typedef long long LL ; typedef pair<int,int> PII;void solve() {string a,b, c;cin>>a>>b>>c;string s(3,a);s[0]a[0];s[1]b[0];s[2…

Java集合(八股)

这里写目录标题 Collection 接口List 接口ArrayList 简述 1. ArrayList 和 LinkedList 区别&#xff1f;⭐️⭐️⭐️⭐️2. ArrayList 和 Array 的区别&#xff1f;⭐️⭐️⭐️ArrayList 和 Vector 区别&#xff1f;⭐️⭐️ArrayList 的扩容机制&#xff1f;⭐️⭐️⭐️ Qu…

18063 圈中的游戏

### 思路 1. 创建一个循环链表表示围成一圈的 n 个人。 2. 从第一个人开始报数&#xff0c;每报到 3 的人退出圈子。 3. 重复上述过程&#xff0c;直到只剩下一个人。 4. 输出最后留下的人的编号。 ### 伪代码 1. 创建一个循环链表&#xff0c;节点表示每个人的编号。 2. 初始…

Vue3+TS项目封装一个公共的el-table组件二次封装

前言 支持动态传入列&#xff0c;列内容可以指定插槽&#xff0c;指定格式化显示 样式没太写&#xff0c;主要分享基础功能封装 效果 Table组件代码BaseTable.vue <template><el-table :data"data" border><template v-for"col in columns&q…

通过防火墙分段增强网络安全

什么是网络分段‌ 随着组织规模的扩大&#xff0c;管理一个不断扩大的网络成为一件棘手的事情&#xff0c;同时确保安全性、合规性、性能和不间断的运行可能是一项艰巨的任务。为了克服这一挑战&#xff0c;网络管理员部署了网络分段&#xff0c;这是一种将网络划分为更小且易…

react18基础教程系列-- 框架基础理论知识mvc/jsx/createRoot

react的设计模式 React 是 mvc 体系&#xff0c;vue 是 mvvm 体系 mvc: model(数据)-view(视图)-controller(控制器) 我们需要按照专业的语法去构建 app 页面&#xff0c;react 使用的是 jsx 语法构建数据层&#xff0c;需要动态处理的的数据都要数据层支持控制层: 当我们需要…

YoloV8 trick讲解

1.将 YOLOv5 的 C3结构换成了梯度流更丰富的 C2f结构: C3 C3 模块的设计灵感来自 CSPNet&#xff0c;其核心思想是将特征图的部分通道进行分割和并行处理&#xff0c;目的是减少冗余梯度信息&#xff0c;同时保持较高的网络表达能力。C3 结构与传统的残差结构类似&#xff0c;但…

PMBOK® 第六版 定义活动

目录 读后感—PMBOK第六版 目录 定义活动的过程强调专业分工&#xff0c;将工作包分解成不同的活动&#xff0c;再由专业人员将这些活动细化为具体任务&#xff0c;分配给项目成员完成。 在软件开发项目中&#xff0c;定义活动将项目流程细化为需求分析、系统设计、编码、测试…

了解MySQL 高可用架构:主从备份

为了防止数据库的突然挂机&#xff0c;我们需要对数据库进行高可用架构。主从备份是常见的场景&#xff0c;通常情况下都是“一主一从/(多从)”。正常情况下&#xff0c;都是主机进行工作&#xff0c;从机进行备份主机数据&#xff0c;如果主机某天突然意外宕机&#xff0c;从机…

CPU 和 GPU:为什么GPU更适合深度学习?

目录 什么是 CPU &#xff1f; 什么是 GPU &#xff1f; GPU vs CPU 差异性对比分析 GPU 是如何工作的 &#xff1f; GPU 与 CPU 是如何协同工作的 &#xff1f; GPU vs CPU 类型解析 GPU 应用于深度学习 什么是 CPU &#xff1f; CPU&#xff08;中央处理器&#xff09;…

学习大数据DAY57 新的接口配置

作业  完成 API 接口和文件的接入, 并部署到生产调度平台, 每个任务最后至少 要有两条 不报错 的日志, 报错就驳回作业  作业不需要复制日志 API Appliation Program Interface 应用程序接口 > JSON 的地址 客户需求: 把 https://zhiyun.pub:9099/site/c-class…

nginx安装及vue项目部署

安装及简单配置 在usr/local下建好nginx文件夹&#xff0c;下载好nginx-1.26.2.tar.gz压缩文件.安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel gcc、gcc-c # 主要用来进行编译相关使用 openssl、ope…

大模型笔记03--快速体验dify

大模型笔记03--快速体验dify 介绍部署&测试部署 dify测试dify对接本地ollama大模型对接阿里云千问大模型在个人网站中嵌入dify智能客服 注意事项说明 介绍 Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;…