Springboot + Mysql8 读写分离实战

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 在实际的生产环境中,为了确保数据库的稳定性,我们一般会给数据库配置双机热备机制。

在实际的生产环境中,为了确保数据库的稳定性,我们一般会给数据库配置双机热备机制,这样在master数据库崩溃后,slave数据库可以立即切换成主数据库,通过主从复制的方式将数据从主库同步至从库,在业务代码中编写代码实现读写分离(让主数据库处理 事务性增、改、删操作,而从数据库处理查询操作)来提升数据库的并发负载能力。


3.png


下面我们使用最新版本的Mysql数据库(8.0.16)结合SpringBoot实现这一完整步骤(一主一从)。


安装配置mysql



  • 准备两台虚拟机用作安装mysql,并将下载后的文件mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz上传至服务器/app/mysql


  • 192.168.249.131 CENTOS7 主
  • 192.168.249.129 CENTOS7 从


  • 查看防火墙状态,如果启动需要先关闭防火墙


servicefirewalldstatus##查看防火墙状态servicefirewalldstop##关闭防火墙


  • 使用如下命令将xz文件解压成tar文件
    xz -d mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz


  • 解压安装包
    tar -xvf mysql-8.0.16-linux-gl-ibc2.12-x86_64.tar


  • 在/app/mysql下建立data文件夹,用于存放数据


  • 创建mysql用户组和mysql用户


groupaddmysql##创建用户组useradd-gmysql-d/app/mysqlmysql##在用户组下创建mysql用户并授权相关目录groupdelmysql##删除用户组名(若报已存在相关用户组)userdelmysql##删除用户(若报已存在相关用户)


  • 初始化安装mysql数据库
    ./mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld --user=mysql --basedir=/app/mysql --datadir=/app/mysql/data --initialize


2019-07-01T02:05:52.681626Z0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it'isdeprecatedandwillberemovedinafuturerelease.
2019-07-01T02:05:52.681694Z0 [System] [MY-013169] [Server] /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld8.0.16) initializingofserverinprogressasprocess14792019-07-01T02:05:52.681726Z0 [ERROR] [MY-010338] [Server] Can't find error-message file '/app/mysql/share/errmsg.sys'. Check error-message file location and 'lc-messages-dir' configuration directive.2019-07-01T02:05:55.713747Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: xa6(H>rK/r<E2019-07-01T02:05:57.303240Z 0 [System] [MY-013170] [Server] /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.16) initializing of server has completed


注意,此时mysql会生成一个默认的临时密码,如上图所示,需要先保存下来然后修改


  • 建立mysql服务并增加执行权限
    cp mysql-8.0.16-linux-glibc2.12-x86_64/support-files/mysql.server /etc/init.d/mysqld


  • 修改mysql配置文件 vi /etc/my.cnf 增加如下配置


[mysqld]
port=3306basedir=/app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64datadir=/app/mysql/datasocket=/tmp/mysql.socksymbolic-links=0[mysqld_safe]
log-error=/app/mysql/data/log/error.logpid-file=/app/mysql/data/mysql.piduser=mysqltmpdir=/tmpcharacter_set_server=utf8default-storage-engine=INNODBinit_connect='SET NAMES utf8'!includedir/etc/my.cnf.d


如果报日志权限相关错误,请先建立对应日志文件,并给mysql用户授权

chown -R mysql:mysql /app/mysql/data/log/error.log


  • 启动mysql服务
    service mysqld start


  • 建立mysql客户端软连接
    ln -s /app/mysql/mysql-8.0.16-linux-glibc2.12-x86_64/bin/mysql /usr/local/bin/mysql


  • 登录mysql修改密码


mysql-uroot-p密码##登录ALTERUSER'root'@'localhost'IDENTIFIEDWITHmysql_native_passwordBY'000000';


  • 设置远程登录


usemysql;
updateusersethost='%'whereuser='root'limit1;
flushprivileges;


配置mysql主从同步(binlog)

复制原理


  • Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件,这些记录叫做二进制日志事件(binary log events)


  • Slave通过I/O线程读取Master中的binary log events并写入到它的中继日志(relay log)


  • Slave重做中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完成数据在本地的存储,从而实现将改变反映到它自己的数据(数据重放)


复制要求


  • 主从服务器操作系统版本和位数一致


  • Master和Slave数据库的版本要一致


  • Master和Slave数据库中的数据要一致


  • Master开启二进制日志,Master和Slave的server_id在局域网内必须唯一


配置步骤

主数据库(192.168.249.131)


  • 创建同步用户并授权


CREATEUSER'slave'@'192.168.249.129'IDENTIFIEDWITH'mysql_native_password'BY'000000';
GRANTREPLICATIONSLAVE, REPLICATIONCLIENTON*.*TO'slave'@'192.168.249.129';
FLUSHPRIVILEGES;


注意这里创建用户时需要选用mysql_native_password加密方式插件,否则默认会使用caching_sha2_password加密方式,这样在同步的时候需要使用SSL的身份进行验证,为了方便简单,我们直接采用mysql_native_password方式


  • 修改配置/etc/my.cnf,新增如下配置,开启binlog,并重启mysql服务


[mysqld]
#开启二进制日志功能log-bin=mysql-bin#设置server_id,,注意在网段内要唯一server-id=131#(可选配置)要同步的数据库名,要同步多个数据库,就多加几个replicate-db-db=数据库名binlog-do-db=mydb#(可选配置)要忽略的数据库binlog-ignore-db=mysql


  • 查看主服务器状态
    show master status


1.png


注意看里面的参数,特别前面两个File和Position,在从服务器(Slave)配置主从关系会有用到的。


从数据库(192.168.249.129)


  • 修改/etc/my.cnf,新增如下配置,并重启服务


[mysqld]
server-id=129log-bin=mysql-binreplicate-do-db=mydbreplicate-ignore-db=mysql


  • 在slave中设置master信息,指定同步位置


stopslave;
changemastertomaster_host='192.168.249.131',master_user='slave',master_password='000000',master_log_file='mysql-bin.000001',master_log_pos=155;
startslave;


参数说明:


master_host=‘192.168.249.131’ ## Master的IP地址


master_user=‘slave’ ## 用于同步数据的用户(在Master中授权的用户)


master_password=‘000000’ ## 同步数据用户的密码


master_port=3306 ## Master数据库服务的端口


masterlogfile=‘mysql-bin.000001’ ##指定Slave从哪个日志文件开始读复制数据(Master上执行命令的结果的File字段)


masterlogpos=155 ## 从哪个POSITION号开始读(Master上执行命令的结果的Position字段)


masterconnectretry=30 ##当重新建立主从连接时,如果连接建立失败,间隔多久后重试。单位为秒,默认设置为60秒,同步延迟调优参数。


  • 查看从服务器状态
    show slave status\G;


2.png


至此数据库层面主从配置完成。


SpringBoot中配置主从读写分离


在主从模式下请遵守如下规则:


主数据库 只执行 INSERT,UPDATE,DELETE 操作


从数据库 只执行SELECT操作


我们这里使用开源项目[dynamic-datasource-spring-boot-starter](https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter/wikis/)作为读写分离的工具包


使用方法


  1. 在mydb主数据库中建立一个简单数据表user,建好后从数据库会自动同步


DROPTABLEIFEXISTS`user`;
CREATETABLE`user` (
`id`int(11) NOTNULLAUTO_INCREMENT,
`account`varchar(255) COLLATEutf8mb4_unicode_ciDEFAULTNULL,
`name`varchar(255) COLLATEutf8mb4_unicode_ciDEFAULTNULL,
`position`varchar(255) COLLATEutf8mb4_unicode_ciDEFAULTNULL,
PRIMARYKEY (`id`)
) ENGINE=InnoDBAUTO_INCREMENT=5DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_unicode_ci;


  1. 引入相关依赖


<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.0.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></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></dependencies>


  1. 配置数据源


spring:
datasource:
dynamic:
primary: master#设置默认的数据源或者数据源组,默认值即为masterstrict: false#设置严格模式,默认false不启动. 启动后再为匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
datasource:
master:
type: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.249.131:3306/mydb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=falseusername: rootpassword: '000000'driver-class-name: com.mysql.cj.jdbc.Driverslave_1:
type: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.249.129:3306/mydb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=falseusername: rootpassword: '000000'driver-class-name: com.mysql.cj.jdbc.Driver


  1. 在启动类入口加入mybatis扫描包


@SpringBootApplication@MapperScan("com.jianzh5.dynamic.mapper")
publicclassDynamicDatsourceBootstrap {    
publicstaticvoidmain(String[] args) {        
SpringApplication.run(DynamicDatsourceBootstrap.class, args);
    }
}


  1. 建立实体类User


@DatapublicclassUser {
privateintid;
privateStringaccount;
privateStringname;
privateStringposition;
}


6.建立mapper接口文件,新增两个方法addUser(User user),getById(int id)


publicinterfaceUserDao {
@Insert("INSERT INTO user(account, name, position) VALUES(#{account}, #{name}, #{position})")
@Options(useGeneratedKeys=true,keyProperty="id")
intaddUser(Useruser);
@Select("SELECT * FROM user WHERE id = #{id}")
UsergetById(intid);
}


  1. 建立Service相关实现


publicinterfaceUserService {
intaddUser(Useruser);
UsergetById(intid);
}
@ServicepublicclassUserServiceImplimplementsUserService {
@ResourceprivateUserDaouserDao;
@OverridepublicintaddUser(Useruser) {
returnuserDao.addUser(user);
    }
@DS("slave")
@OverridepublicUsergetById(intid) {
returnuserDao.getById(id);
    }
}


由于在数据源中配置了primary: master,默认操作都会从主库执行,使用注解@DS切换数据源,此注解也可直接用于类文件上,同时存在方法注解优先于类上注解。


  1. 编写单元测试进行测试


publicclassUserServiceTestextendsDynamicDatsourceBootstrapTests {
@AutowiredprivateUserServiceuserService;
@TestpublicvoidtestAddUser(){
Useruser=newUser();
user.setName("李四");
user.setAccount("sili");
user.setPosition("JAVA开发工程师");
inti=userService.addUser(user);
System.out.println(user);
    }
@TestpublicvoidtestGetById(){
intid=4;
Useruser=userService.getById(id);
Assert.assertEquals("sanzhang",user.getAccount());
    }
}


  1. 通过观察执行日志,发现读写数据库会根据@DS注解进行切换,至此Springboot集成数据库主从读写分离完成。
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
176 66
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
25天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
45 5
|
1月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
57 8
|
1月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
65 9
|
1月前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
283 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
97 5
|
2月前
|
架构师 关系型数据库 MySQL
MySQL最左前缀优化原则:深入解析与实战应用
【10月更文挑战第12天】在数据库架构设计与优化中,索引的使用是提升查询性能的关键手段之一。其中,MySQL的最左前缀优化原则(Leftmost Prefix Principle)是复合索引(Composite Index)应用中的核心策略。作为资深架构师,深入理解并掌握这一原则,对于平衡数据库性能与维护成本至关重要。本文将详细解读最左前缀优化原则的功能特点、业务场景、优缺点、底层原理,并通过Java示例展示其实现方式。
124 1
|
1月前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
124 0
|
1月前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
34 0