SpringBoot+ShardingSphere+Mybatis实现Mysql8读写分离

news2024/11/23 23:45:19

场景

CentOS7安装Mysql8并进行主从复制配置:

CentOS7安装Mysql8并进行主从复制配置_霸道流氓气质的博客-CSDN博客

在上面搭建起来Mysql之间的主从复制的基础上,在SpringBoot项目中实现Mysql数据的

读写分离,即写入操作一个库,读取操作一个库。

Apache ShardingShpere

Apache ShardingSphere 是一款分布式 SQL 事务和查询引擎,可通过数据分片、弹性伸缩、加密

等能力对任意数据库进行增强。

Apache ShardingSphere

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

1、添加shardingsphere的maven依赖

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>

这里使用mybatis,所以完整的依赖为

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
    </dependencies>

2、修改application.yml配置文件,将数据源修改为如下,详细配置见注释和官网文档

# 数据源
spring:
  application:
    name: Demo
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    # 参数配置 ,显示SQL
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名 任意取
      names: ds1,ds2
      # 给master-ds1配置数据库连接信息
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
       jdbc-url:jdbc:mysql://192.168.148.141:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: Aa_123456

      ds2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
       jdbc-url:jdbc:mysql://192.168.148.142:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: Aa_123456

    #配置默认数据源ds1
    sharding:
      # 默认数据源,主要用于写,注意一定要配置读写分离;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。
      default-data-source-name: ds1
    # 配置数据源的读写分离;前提需要做数据库的主从复制;可以不写,会按照默认随机策略
    masterslave:
      # 配置主从名称,任意取名字
      name: ms
      # 配置主库 ,负责数据的写入
      master-data-source-name: ds1
      # 配置从库
      slave-data-source-names: ds2
      # 配置 slave 节点的负载均衡策略 :轮询机制
      load-balance-algorithm-type: round_robin

上面配置两个数据库的数据源以及主库等操作。

完整配置文件

# 开发环境配置
server:
  # 服务器的HTTP端口,默认为8080
  port: 996
  servlet:
    # 应用的访问路径
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # tomcat最大线程数,默认为200
    max-threads: 800
    # Tomcat启动初始化的线程数,默认值25
    min-spare-threads: 30

# 数据源
spring:
  application:
    name: Demo
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    # 参数配置 ,显示SQL
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名 任意取
      names: ds1,ds2
      # 给master-ds1配置数据库连接信息
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
       jdbc-url:jdbc:mysql://192.168.148.141:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: Aa_123456

      ds2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
       jdbc-url:jdbc:mysql://192.168.148.142:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: Aa_123456

    #配置默认数据源ds1
    sharding:
      # 默认数据源,主要用于写,注意一定要配置读写分离;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。
      default-data-source-name: ds1
    # 配置数据源的读写分离;前提需要做数据库的主从复制;可以不写,会按照默认随机策略
    masterslave:
      # 配置主从名称,任意取名字
      name: ms
      # 配置主库 ,负责数据的写入
      master-data-source-name: ds1
      # 配置从库
      slave-data-source-names: ds2
      # 配置 slave 节点的负载均衡策略 :轮询机制
      load-balance-algorithm-type: round_robin

# mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml    # mapper映射文件位置
  type-aliases-package: com.badao.demo.entity    # 实体类所在的位置
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #用于控制台打印sql语句


3、编写各层代码进行读写分离测试

主库新建一个测试表t_user

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` int NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `age` int NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

新建实体类

@Data
public class User implements Serializable {

    private static final long serialVersionUID = -5514139686858156155L;

    private Integer id;

    private Integer userId;

    private String name;

    private Integer age;

}

其他mapper和service等层代码省略。直接新建controller包含新增和查询接口

@RequestMapping("user")
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("save")
    public String save() {
        User user = new User();
        user.setUserId(new Random().nextInt( 1000 ) + 1);
        user.setName("张三"+user.getUserId());
        user.setAge(new Random().nextInt( 80 ) + 1);
        userService.insert(user);
        return "save success";
    }

    @RequestMapping("findAll")
    public String findAll() {
        List<User> all = userService.findAll();
        return all.toString();
    }
}

4、测试以上两个接口

分别调用新增和查询所有的接口,可以发现走的是不同的数据库。

 

5、读写分离读延迟的问题如何解决

刚插入一条数据,然后马上就要去读取,这个时候有可能会读取不到?

归根到底是因为主节点写入完之后数据是要复制给从节点的,读不到的原因是复制的时间比较长,

也就是说数据还没复制到从节点,你就已经去从节点读取了。

除了业务层面妥协,是否操作完之后马上要进行读取,可以对于这类的读取直接走主库,

当然Sharding-JDBC也是考虑到这个问题的存在,所以给我们提供了一个功能,

可以让用户在使用的时候指定要不要走主库进行读取。在读取前使用下面的方式进行设置

    @RequestMapping("findMasterAll")
    public String findMasterAll() {
        // 强制路由主库
        HintManager.getInstance().setMasterRouteOnly();
        List<User> all = userService.findAll();
        return all.toString();
    }

可以看到此时强制查询时也走主库

 

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

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

相关文章

为什么重写 equals 方法要重写 hashCode 方法

前言 看了挺多关于这个问题相关的文章&#xff0c;发现回答缺少因果逻辑。直到看了一篇文章提到 《Effective Java》中有关于这个问题的答案。于是找了电子书看了一下&#xff0c;查看相关源码理清了因果逻辑&#xff0c;得出怎样回答这个问题比较好。 1 hashCode 的通用约定…

k8s 如何升级应用

如何升级应用 在之前的分享中&#xff0c;我们知道一个程序如何放到容器中&#xff0c;一个镜像如何生成 pod&#xff0c; pod 的创建&#xff0c;运行&#xff0c;管理&#xff0c;删除过程&#xff0c;挂载等等 那么我们有没有想过&#xff0c;在真正的生产环境中&#xff…

golang 验证器库go-playground/validator实践

当我们将一个接口值传递给一个 reflect.ValueOf 函数调用时&#xff0c;此调用返回的是代表着此接口值的动态值的一个 reflect.Value 值。我们必须通过间接的途径获得一个代表一个接口值的 reflect.Value 值。 reflect.Value 类型有很多方法&#xff08;Package reflect - The …

【字符流】编码解码问题

字符流中编码解码问题 字符流抽象基类&#xff1a; Reader&#xff1a;字符输入流的抽象类Writer&#xff1a;字符输出流的抽象类 字符流中和编码和解码问题相关的两个类&#xff1a; InputStreamReader&#xff1a;是从字节流到字符流的桥梁&#xff0c;它读取字节并使用指…

Jupyter Notebook 后台启动

进入用户目录 cd 指定目录 激活环境 conda activate 环境名 Note&#xff1a; 注意&#xff1a;无法导入依赖包&#xff0c;查看是否激活对应环境。 后台启动 jupyter notebook&#xff0c;或者服务器上启动 可通过浏览器访问 nohup jupyter notebook --allow-root& …

C语言——通讯录的实现

前面的文章介绍了C语言中的 指针、自定义类型等模块&#xff0c;这篇文章将通过编写实现通讯录的代码对这些模块进行应用和进一步加深理解&#xff1a; 目录 1. 通讯录主要功能设计&#xff1a; 2. 通讯录的实现——主页面&#xff1a; 3. 通讯录的实现——保存个人信息&am…

CS 144 Lab Three-- the TCP sender

CS 144 Lab Three -- the TCP sender TCPSender 功能如何检测丢包TCPSender 要求TCPSender 状态转换图TCPSender 实现测试 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Three 对应的PDF: Lab Checkpoint 3: the TCP sender TCPSender 功能 TCP Sender 负责将数据以…

27 Deep Belief Network

文章目录 27 Deep Belief Network——深度信念网络27.1 DBN是什么&#xff1f;27.2 为什么要使用DBN27.2.1 DBN的思想是怎么来的&#xff1f;27.2.2 RBM的叠加可以提高ELBO 27.3 训练方式 27 Deep Belief Network——深度信念网络 27.1 DBN是什么&#xff1f; DBN(Deep Belie…

【机器学习】分类算法 - KNN算法(K-近邻算法)KNeighborsClassifier

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 K-近邻算法 1、什么是K-近邻算法&#xff1f;2、K-近邻算法API3、…

FastDFS与Springboot集成

&#x1f680; FastDFS与Springboot集成 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风…

139、仿真-基于51单片机一氧化碳(CO)气体检测仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、设计功能 二、Proteus仿真图​编辑 三、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&#xff1…

【K8S系列】深入解析k8s网络插件—Calico

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 Kubernetes (k8s) 是一个容器编…

视频理解多模态大模型(大模型基础、微调、视频理解基础)

转眼就要博0了&#xff0c;导师开始让我看视频理解多模态方向的内容&#xff0c;重新一遍打基础吧&#xff0c;从Python&#xff0c;到NLP&#xff0c;再到视频理解&#xff0c;最后加上凸优化&#xff0c;一步一步来&#xff0c;疯学一个暑假。写这个博客作为我的笔记以及好文…

代码随想录算法训练营第55天|392 115

392 双指针法很简单 class Solution { public:bool isSubsequence(string s, string t) {int i0;for (int j0; j<t.size() && i<s.size(); j) {if (t[j]s[i]) {i;}}return is.size();} }; 用动态规划来写的话 逻辑其实跟1143 1035是一样的 最后返回看dp[s.size…

Vue element el-input输入框 实现 ’空格+enter’组合键:换行,enter:发送,使用keydown和keyup键盘事件来实现

需求 输入框 &#xff0c;输入内容后 &#xff0c;按enter空格键 换行&#xff0c;按enter键 发送调取接口 思路 jquery的也分为三个过程&#xff0c;在事件名称上有所不同 1、某个键盘的键被松开&#xff1a;keyup 2、某个键被按下&#xff1a;keydown 3、某个键盘的键被按…

基于查找表(lookup table,LUT)方法反演植被参数

LUT指显示查找表&#xff08;Look-Up-Table)&#xff0c;本质上就是一个RAM。它把数据事先写入RAM后&#xff0c;每当输入一个信号就等于输入一个地址进行查表&#xff0c;找出地址对应的内容&#xff0c;然后输出。 LUT的应用范围比较广泛&#xff0c;例如&#xff1a;LUT(Lo…

机器学习:Self-supervised Learning for Speech and image

review : self-supervised learning for text Self-supervised learning for speech 使用Speech版本的bert能比较好的作用于语音任务上&#xff0c;如果没有self-supervised的话&#xff0c;别的模型可能需要上万小时的数据。 Superb ytb课程&#xff1a;MpsVE60iRLM工具&…

vulnhub打靶--lampiao

目录 vulnhub--lampiao1.扫描主机端口&#xff0c;发现1898端口部署web2.打开robots.txt发现CHANGELOG.txt文件3.发现drupal更新日志&#xff0c;drupal这个版本有公开exp。利用msf打下4.执行uname -a 或者上传漏洞suggest脚本&#xff0c;可以发现有脏牛提权5.上传脚本到目标&…

2023年7月19日,锁升级,网络编程

锁升级 锁的四种状态&#xff1a;无锁、偏向锁、轻量级锁、重量级锁&#xff08;JDK1.6&#xff09; 无锁&#xff1a;操作数据时不会上锁 偏向锁&#xff1a;会偏向于第一个访问锁的线程&#xff0c; 如果在运行过程中&#xff0c;只有一个线程访问加锁的资源&#xff0c;不存…

JavaWeb+Vue分离项目实现增删改查

文章目录 前言数据库后端代码util 代码listener 代码filter 代码po 代码dao 层增删改查代码service 层增删改查代码controller 层增删改查代码 前端代码查询操作删除功能增加功能修改方法路由传参修改会话存储修改 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&…