前言:最近一个项目用到了ShardingSphere
用于读写分离,于是琢磨着在本地写个demo玩玩,所以就有了这。一般而言:mysql读写分离的前提就是主从复制
。如果没有主从复制,那么读写分离就没什么用了。比如你从主库写数据,然后从从库读数据,但是主库的数据都没同步到从库,那你岂不是读了个寂寞,对吧,显然是读取不到主库写入的数据的。
本篇大概内容
windows
下安装3个mysql服务
,端口分别是3306(主),3307(从),3308(从);一主两从
,主库写,从库读;Sharding-jdbc+jpa+druid+springboot2
实现读写分离。篇幅有点长,需要点耐心
环境说明: 我这里是基于mysql5.7.29
模拟一主二从的操作,其他mysql版本可能会有不兼容,暂不在本篇讨论范围之内。具体实现原理这里不做说明,感兴趣的朋友可自行了解。
相信很多朋友原本就已经安装过了mysql服务,所以只需要再安装两个mysql服务即可,那么,如何安装呢?
我这里给出的方法如下:
原本已安装mysql不做处理,重新解压之前的安装包,并且解压两次,分别重命名,至于如何命名,请大家随意,没有影响的,我这里如下所示:
相信这一步,大家都没有任何问题。那么,我们继续下一步。
复制之前mysql服务的my.ini
文件(没有就新建一个),也就是mysql的配置文件
,分别复制
到两个新的目录之下,我这里是D:/AllDownload/mysql-5.7.29-winx64-3307
和 D:/AllDownload/mysql-5.7.29-winx64-3308
,因为3307和3308的操作完全是一样的,所以我这里仅详细介绍3307的操作,3308就交给大家自己处理啦。
复制之后,需要对配置文件进行修改,我这里贴出我的3307对应的my.ini配置文件:
[client]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
# 设置3307端口 默认是3306
port = 3307
# 设置mysql的安装目录
basedir=D:/AllDownload/mysql-5.7.29-winx64-3307
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
datadir=D:/AllDownload/mysql-5.7.29-winx64-3307/data
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
# 允许最大连接数
max_connections=500
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
group_concat_max_len = 1024000
max_allowed_packet=1073741824
大家看一眼应该就能明白了,3306、3307、3308的配置文件区别就在于port
以及basedir
以及datadir
不一样,我这里只是贴出我的3307配置文件,大家根据自己实际情况来填写就好
。
datadir
了吗,其值为D:/AllDownload/mysql-5.7.29-winx64-3307/data
。其中data
文件夹是不存在的,需要我们去到对应的文件夹下新建。新建之后如下:管理员身份打开cmd控制台
,一定要以管理员身份,否则可能会因为权限问题导致后续命令执行失败!进入到mysql3307的bin目录下
,如下所示:不要直接执行
:mysqld install mysql3307 --defaults-file="D:\AllDownload\mysql-5.7.29-winx64-3307\my.ini"
为什么不要直接执行
呢?因为很多朋友肯定都是已经配置了mysql环境变量
的,直接执行意味着什么呢?聪明的你,应该已经想到了,直接执行的话,会执行mysql3306服务的bin目录下的mysqld命令,而不是当前3307服务bin目录下的mysqld,那么,可能就会发生服务已存在之类的错误,或者其他错误。
所以,如何处理?最好是先删除mysql环境变量的配置
,也就是 MYSQL_HOME
啥的。
删除之后,再次执行上述命令,其中mysql3307
是服务名,是为了区分于mysql服务的。
如果不想删除的话,试试加上.\,表示执行当前目录的mysqld,我没试过不知道效果。
install之后,就是初始化
,初始化命令如下(务必记下末尾的密码):
mysqld --initialize --user=mysql3307 --console
其实初始化就是生成data目录以及其中的文件,执行失败请删除data目录,找到问题后重新执行初始化。
如果一切ok,那么接下来,启动mysql3307服务即可,启动命令:
net start mysql3307
启动成功,登录看看,一定要加-P 3307
不然就会默认登录到3306端口了
mysql -u root -p -P 3307
然后提示要求输入密码,初始化的时候会打印出密码。
到此,mysql3307服务安装启动完成,mysql3308也是同样的流程,我就不再赘述啦。
都ok的话,记得把mysql环境变量再配置一下。
异常问题处理: 上面是一切顺利的情况下,如果中途出现问题了,如何处理呢?因为大家情况不一,我也无法全部说到,反正百度基本就完事了。
但是,严格按照我上面的流程,基本都ok的。
我再贴一下mysql3307 mysql3308服务安装ok之后,我的注册表编辑器的信息:
这个注册表信息的mysql3307 mysql3308,当你执行完相应的install操作的时候,就会出现
,我这里mysql3307服务
的数值数据具体如下:
D:\AllDownload\mysql-5.7.29-winx64-3307\bin\mysqld --defaults-file=D:\AllDownload\mysql-5.7.29-winx64-3307\my.ini mysql3307
如果
你遇到
什么问题
,可以看看这里是否正确
,因为事先安装了mysql环境变量,没有删除环境变量而直接install
的话,你这里的目录
就会对应到3306
那边去了,就会导致后续一系列的操作无法成功。
如果没有按照流程而导致失败的,卸载重装吧,或者直接修改注册表的信息也行,这里说说如何卸载
:
管理员身份打开cmd窗口,首先查询对应的mysql服务是否存在,查询命令:sc query mysql3307
如果存在,直接删除,删除命令:sc delete mysql3307
,再次查询就查不到了;
删除data目录(文件夹)下的所有文件,其实data目录也是可以删除的,初始化的时候会生成;
重新执行安装流程。
mysql3307和mysql3308服务均启动成功后,接下来就得配置主从复制了。
主从数据库的配置和代码无关,只需要配置mysql相关的设置即可。
我这里贴出3306的 my.ini
配置文件
default-character-set=utf8
[mysqld]
# 设置3306端口
port = 3306
# 设置mysql的安装目录
basedir=D:\AllDownload\mysql-5.7.29-winx64
# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错
datadir=D:\AllDownload\mysql-5.7.29-winx64\data
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
# 允许最大连接数
max_connections=500
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
group_concat_max_len = 1024000
max_allowed_packet=1073741824
# 主从复制配置 3306端口为主 其他为从
# 服务id,在主从中需要保证唯一
server-id=1
# 启用二进制日志 其实主从同步就是通过线程读取该日志文件执行的 每次mysql服务重新启动都会生成新的二进制文件
log-bin=mysql-bin
# 需要执行主从同步复制的数据库名称
binlog-do-db=test
# 不需要执行主从同步复制的数据库名称,一般Mysql自带的数据库就没必要了
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
# 自动清理20天前的log文件
expire_logs_days=20
具体什么意思已经写了注释了,3307和3308也是一样的,唯一的区别在于server-id不一样
然后,重新启动3306服务,windows下如何重启mysql我就不多说什么了(2种方法):
1.cmd窗口 net stop mysql 先停止,net start mysql 再启动
2.直接打开服务,就是在win+r 输入 services.msc
回车,找到mysql,点击重启即可,如下:
重启之后,首先查看是否开启了log_bin日志:
show variables like "%log_bin%";
然后配置一个新用户,并且配置主从复制的权限,用于执行主从复制,一般不会使用root用户,所以这里配置一个新用户,用户名大家随意取,开心就好。
//说明:创建用户slave01,密码是ccc
//@后面表示允许连接的客户端ip地址 %表示允许所有ip地址
create user 'slave01'@'%' identified by 'ccc';
//格式:grant 权限 on 数据库名.表名 to 用户@登录主机 identified by "用户密码";
//@后面的ip地址为允许连接的客户端ip地址 %表示允许所有ip地址
//如果是mysql8 这个命令是不可用的 会报错 可用这条(grant replication slave on *.* to 'slave01'@'%' with grant option;)
grant replication slave on *.* to 'slave01'@'%' identified by 'ccc';
新增的slave01用户可以在mysql库的user表看到。
配置完毕之后,查看此时msater的状态:
File:二进制文件,用户主从复制的,每次mysql服务重启该文件都会改变;
Position:二进制文件的位置,主从复制开始的位置;
其他参数大家有兴趣可以自行查阅。
到此,主服务信息配置完毕,接下来重启mysql3307服务,配置文件和3306几乎一样,除了server-id以及各自的安装目录,数据存放目录。
重启之后,登录 mysql -u root -p -P 3307 执行如下命令开启从库复制功能
change master to master_host='127.0.0.1', master_port=3306, master_user='slave01', master_password='ccc', master_log_file='mysql-bin.000001', master_log_pos=154;
命令解析:
//master_host: 主服务器的IP 注意:大家根据自己实际情况填写
//master_user: 主服务器上新创建的用户名
//master_password: 用户的密码
//master_port: 主服务器的端口,如果未曾修改,默认即可。
//master_log_file: 主服务器二进制日志文件的名称,填写查看主服务器的master状态时显示的File的值
//master_log_pos: 日志的位置,填写查看主服务器的master状态时显示的Position的值
//然后开启从库功能
start slave;
以上两条命令执行完毕,查看从库状态:
show slave status \G
查看结果如下:
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: slave01
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 688
Relay_Log_File: LAPTOP-FRT2GIQ8-relay-bin.000002
Relay_Log_Pos: 854
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 688
Relay_Log_Space: 1071
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 3751bfa8-8784-11ea-8e5b-5c80b6566b2e
Master_Info_File: D:\AllDownload\mysql-5.7.29-winx64-3307\data\master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
如果 Slave_IO_Running
和 Slave_SQL_Running
的值都为 Yes
,则说明主从复制的所有配置已成功,即从服务器已经可以自动与主服务器的数据库数据实现同步了。
mysql3308也是同样的操作,我就不再重复了。
一切OK之后,我们可以试一试,我这里用navicat分别连接3个mysql服务,然后在3306创建test数据库,并且添加t_user表。3307和3308也会跟着自动创建
test数据库库和t_user表,主从复制完成
:
如果在主服务器执行test库之外的操作,从服务器是不会有任何变化的,因为设置为仅同步test库;
如果在从服务器的任何库执行写入操作,主服务器是不会有任何变化的,除非设置成互为主从。
好了,主从复制完成,接下来是读写分离操作,这块主要涉及到代码,上面更多的是安装配置。
首先是ShardingSphere官方文档
感兴趣的可以看看,话不多说,直接上代码,因为是个小demo,所以代码很简单,基本没有,更多的是配置。
代码层面我们完全无需考虑读写分离这些,只要配置文件配置好了就行,该框架会帮我们处理这些问题。
首先引入相关依赖,我这里仅贴出关键依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Sharding-JDBC -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<!-- druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
然后是配置文件application.yml
spring:
shardingsphere:
datasource:
#主从数据源 多个则以逗号分隔开
names: master,slave0,slave1
#主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
username: root
password: root
#从1数据源
slave0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3307/test?useSSL=false&serverTimezone=UTC
username: root
password: root
#从2数据源
slave1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3308/test?useSSL=false&serverTimezone=UTC
username: root
password: root
masterslave:
name: ms
master-data-source-name: master
slave-data-source-names: slave0,slave1
#负载均衡算法 round_robin 代表轮询
load-balance-algorithm-type: round_robin
props:
sql:
show: true
需要注意的是: druid
数据源springboot
版本和sharding-jdbc
的配置存在冲突,如果这样配置直接启动的话,是无法启动
的。
解决办法如下(3种):
1.在启动类排除druid数据源的配置@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
即可;
2.druid数据源maven依赖不要引入spirngboot版本的;
3.使用hikari数据源,但是datasource下的url需要改成jdbc-url;
4.看你们的了…
然后随便写了两个方法,一个查询所有用户,一个添加用户,执行结果如下:
OK,完成。
其他什么分表分库,ShardingSphere也是可以胜任的,主要都是在配置这一块,代码层面就像操作单个数据库一样,非常简单好用。更多功能的话,等待大家自行尝试~