shardingsphere之sharding-proxy读写分离学习笔记

  • 引言
  • 重要提示
    • 演示环境
    • 版本信息
    • 代码示例和参考
  • 读写分离简介
    • 主从复制
      • 主从复制的原理和流程
  • sharding-proxy简介
    • 概念
    • 特点
    • 使用情况
  • 基础环境的搭建
    • docker的安装
    • 安装mysql并配置主从复制
      • 拉取mysql镜像
      • 安装配置master库
      • slave数据库安装配置
      • 出现异常参考
      • 开放阿里云安全组端口
      • 使用客户端连接
      • 简单测试
  • 开始整合sharding-proxy
    • 1、下载sharding-proxy二进制压缩包
    • 2、解压zip包
    • 3、下载mysql驱动包
    • 4、编写yml文件
    • 5、编写config-master_slave.yaml配置文件
    • 6、编写logback.xml日志记录文件
    • 7、启动sharding-proxy
    • 8、客户端连接
    • 9、初始化表格
    • 10、pom.xml加入依赖
    • 11、基础CRUD代码生成
    • 12、编写测试代码
    • 13、运行测试
      • 出现异常参考
      • 报错1
      • 报错2
  • 结语

引言

读写分离在业务中应该是比较常见的,当满足以下几点就可以考虑将数据进行读写分离,减轻数据库的压力和提高响应速度。

(1)业务对数据库是读多写少。
(2)单台服务器或者单个数据库的性能已经不能满足当前业务对数据库大量读取请求。
(3)数据量不是特别巨大,单表还没超过五百万行记录,还不需要分库分表。

重要提示

演示环境

  • 阿里云ECS服务器,CentOS Linux release 7.7.1908 (Core)
  • docker版本:Docker version 19.03.8, build afacb8b
  • 本地系统:windows7

版本信息

  • spring-boot 2.1.6.RELEASE
  • mybatis-plus-generator 3.1.0
  • mybatis-plus-boot-starter 3.1.0
  • druid-spring-boot-starter 1.1.18
  • sharding-proxy 4.0.1
  • mysql 8.0.20

代码示例和参考

用于演示的代码和相关的参考链接已经放到文章的末尾。sql文件放置在sql文件夹,请求信息放置在postMan文件夹,导入postman执行即可。

读写分离简介

读写分离主要分为两步,一是设置数据库实现主从复制,二是在代码层面实现增删改操作到主数据库,读的操作到从数据库,提高数据库的响应能力。

主从复制

太多的理论知识就不在这里赘述了,可以参考MYSQL主从复制原理,有兴趣的可以进行深入研究,选择适合自己的解决方案。

主从复制的原理和流程

(1)Master主库将数据变更DataChanges记录 binlog日志中。
(2)Slave起一个I/O线程连接到Master,dump读取Master的binlog日志并写入到Slave的中继日志Relaylog中
(3)Slave中的SQL线程读取中继日志Relaylog进行SQL回放执行操作,完成主从复制,保证主从最终一致性。

sharding-proxy简介

概念

太多的理论知识我就不赘述了,麻烦自己到官网去看。

sharding-jdbc 和 sharding-proxy对比

特点

配置好之后可作为独立的数据源使用,一个逻辑数据库代理着几个真实数据库,可以用客户端软件比如Navicat Premium 直接去连接和操作。很好的帮助我们处理读写分离的问题,基本不需要对现有的业务代码修改,减少时间成本。

使用情况

目前生产环境已使用的公司

基础环境的搭建

本文是基于阿里云ECS服务器上的docker搭建数据库的,使用docker安装会比传统的方式效率高很多。
下面会把详细的安装步骤和注意的地方一一列出来。这里演示的是一主三从,一个主库master,三个从库slave0,slave1,slave2。

小插曲

对于mysql的安装,一开始我是选择在windows7下面用docker安装的。在安装docker的时候出现一大堆问题,初始化也很麻烦,搞了一个下午也没搞完。所以我转到阿里云上面安装。当然也可以在windows下使用解压的方式安装mysql,这个就自行谷歌吧。

docker的安装

(1)卸载旧的docker,可选。

sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine

(2)安装yum工具类

sudo yum install -y yum-utils \device-mapper-persistent-data \lvm2

(3)启用Docker源

sudo yum-config-manager \--add-repo \https://download.docker.com/linux/centos/docker-ce.repo

(4)安装Docker

sudo yum -y install docker-ce

(5)配置国内的Docker仓库,加快Docker镜像下载速度

vim /etc/docker/daemon.json{"registry-mirrors" : ["https://registry.docker-cn.com"]
}

(6)启动docker

sudo systemctl start docker

(7) 检查是否安装成功,如果出现正常的信息则表示安装成功。

sudo docker info

安装mysql并配置主从复制

拉取mysql镜像

(1)查看mysql镜像版本

可以直接访问 MySQL镜像库地址,直接复制对应的命令即可拉取镜像。

或者使用命令查看

docker search mysql

(2)拉取镜像

docker pull mysql:8.0.20

(3)查看已拉取的镜像

docker images

安装配置master库

(1)运行mysql容器

docker run -itd --name master_3307 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=root mysql:8.0.20

参数介绍

  • –name master_3307 表示容器的名称为master_3307
  • -p 3307:3306 表示将宿主机的3307端口映射到docker的3306端口
  • -e MYSQL_ROOT_PASSWORD=root 表示设置用户root的密码为root
  • mysql:8.0.20 表示使用的镜像版本

小插曲

其实一个镜像可以复用安装成多个容器的,一开始我还以为一个镜像只能对应一个容器呢。

(2)检查是否安装成功

docker ps

下图是成功安装了master,slave0,slave1,slave2结果。
简单备注

docker pull mysql:8.0.20 和docker pull mysql:8.0其实拉取的是同一版本的镜像,这个看镜像ID一致即可知道。

(3)修改配置信息

进入容器内部

docker exec -it master_3307 bash

更新基础软件和安装vim

apt-get update
apt-get install vim

编辑配置文件

vi /etc/mysql/my.cnf

新增信息

[mysqld]
## 同一局域网内注意要唯一
server-id=100
## 开启二进制日志功能,可以随便取(关键)
log-bin=mysql-bin
## 永久设置时区时间
default-time_zone = '+8:00'

修改后保存退出编辑

:wq

备注

  • 按照上面顺序操作可以避免下方两个提示。
bash: vi: command not found
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package vim
  • 配置default-time_zone = ‘+8:00’,不然当datetime类型的默认值为CURRENT_TIMESTAMP时,插入的时间会比系统时间少了8个小时

(4)创建用户并授权,用于在主从库之间同步数据。

进入mysql内部

mysql -uroot -proot

创建同步用户

CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY 'slave';

授予权限

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';

备注

如果本地要用客户端比如Navicat Premium连接,最好设置root的认证方式

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

否则连接可能会报错

2059 - authentication plugin 'caching_sha2_password' cannot be loaded...

(5)查看关键信息

查看两个关键信息,File和Position字段的值后面将会用到,在后面的操作完成之前,需要保证Master库不能做任何操作,否则将会引起状态变化,File和Position字段的值变化。

show master status;

(6)重启容器

退出mysql

exit

退出容器

exit

重启容器

docker restart master_3307

至此,master数据库安装配置完成。

slave数据库安装配置

(1)查看master的容器ip,后面设置会用到

docker inspect --format='{{.NetworkSettings.IPAddress}}' master_3307

(2)运行容器

docker run -itd --name slave0_3308 -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root mysql:8.0.20

(3)进入容器内部

docker exec -it slave0_3308 bash

(4)安装vim

apt-get update
apt-get install vim

(5)修改配置文件

vi /etc/mysql/my.cnf

(6)新增信息

[mysqld]
## 设置server_id,注意要唯一
server-id=1001
## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-slave-bin
## relay_log配置中继日志
relay_log=edu-mysql-relay-bin
## 永久设置时区时间
default-time_zone = '+8:00'

(7)设置主从信息

进入mysql内部

mysql -uroot -proot

重要提示:

如果本地要用客户端比如Navicat Premium连接,最好设置root的认证方式

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

设置主从信息

change master to master_host='172.17.0.2', master_user='slave', master_password='slave', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 3174, master_connect_retry=30,get_master_public_key=1;

参数介绍

  • master_host :Master的地址,指的是容器的独立ip,可以通过下面命令来查看
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称|容器id查询容器的ip
  • master_port:Master的端口号,指的是容器的端口号
  • master_user:用于数据同步的用户
  • master_password:用于同步的用户的密码
  • master_log_file:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
  • master_log_pos:从哪个 Position 开始读,即上文中提到的 Position 字段的值
  • master_connect_retry:如果连接失败,重试的时间间隔,单位是秒,默认是60秒

备注

之所以设置get_master_public_key=1,是因为开启主从复制的时候可能会报出下方的异常。原因是mysql8默认使用插件caching_sha2_password,有些client连接报这个错误,需要拿到server的public key来加密password。

 ERROR 2061 (HY000): Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

(7)查看主从同步状态

show slave status \G;

正常情况下,SlaveIORunning 和 SlaveSQLRunning 都是No,因为我们还没有开启主从复制过程。

(8)开启主从复制

start slave;

(9)再次查询主从同步状态

show slave status \G;


SlaveIORunning 和 SlaveSQLRunning 都是Yes,说明主从复制已经开启。

(10)重启容器

退出mysql

exit

退出容器

exit

重启容器

docker restart slave0_3308

剩余的slave1_3309,slave2_3310的安装配置方法和salve0_3308的方法是一样的,区别就是cnf文件中的server-id不能相同罢了。

出现异常参考

(1)使用start slave开启主从复制过程后,如果SlaveIORunning一直是Connecting,则说明主从复制一直处于连接状态,这种情况一般是下面几种原因造成的,我们可以根据 Last_IO_Error提示予以排除。

  • 网络不通
    解决方法:检查ip,端口
  • 密码不对
    检查是否创建用于同步的用户和用户密码是否正确
  • pos不对
    检查Master的 Position

(2)如果开启主从复制失败,需要修改和重新启动,可参考下方提示

停止主从复制

stop slave;

重置之前的配置信息

reset slave;

修改信息

change master to ......

启动主从复制

 start slave;

备注

如果不重置修改后直接启动可能会报出下方的异常

ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository

开放阿里云安全组端口

到阿里云安全组设置那里开放3307,3308,3309,3310端口,无需开放防火墙firewall端口。

使用客户端连接

小插曲

第一次安装好之后开放了安全组端口,可是使用客户端输入公网ip和账号密码死活连接不上,这个也困扰了我很久。后面过了段时间发现设置的安全组规则不见了,直接重新设置就可以连接了,难以费解。

简单测试

在master库创建一个test数据库,如果从库也有则代表安装成功。至此主从复制的工作已经完成,接下来就是代码层面的读写分离了。

开始整合sharding-proxy

(1)其实大部分的工作都是在编写conf目录下的yml文件,配置好之后应用还是跟以前的方式一样连接和操作,基本不需要对代码进行修改。
(2)逻辑数据源可以配置多个,每个yml文件代表一个逻辑数据源,可手动创建yml文件和编写规则实现多个逻辑数据源的使用
(3)本文演示的是单个逻辑数据源的配置和使用。

1、下载sharding-proxy二进制压缩包

压缩包下载地址

2、解压zip包

注意事项:

(1)解压工具最好选择winrar,不然解压出来的lib文件夹下的jar包由于命名太长被截断,后面将会导致文件找不到,系统启动失败异常。

(2)解压后的文件的路径下最好不要有中文,否则也会导致启动失败。

3、下载mysql驱动包

MySQL Connector/J,下载之后放到lib文件夹下。

4、编写yml文件

(1)首先要编写的是server.yaml,配置全局信息

##治理中心
# orchestration:
#   name: orchestration_ds
#   overwrite: true
#   registry:
#     type: zookeeper
#     serverLists: localhost:2181
#     namespace: orchestration#权限配置
authentication:users:root:               #用户名password: root #密码sharding:password: sharding authorizedSchemas: sharding_db   #只能访问的逻辑数据库#Proxy属性
props:max.connections.size.per.query: 1acceptor.size: 16  #用于设置接收客户端请求的工作线程个数,默认为CPU核数*2executor.size: 16  # Infinite by default.proxy.frontend.flush.threshold: 128  # The default value is 128.# LOCAL: Proxy will run with LOCAL transaction.# XA: Proxy will run with XA transaction.# BASE: Proxy will run with B.A.S.E transaction.proxy.transaction.type: LOCAL   #默认为LOCAL事务proxy.opentracing.enabled: false     #是否开启链路追踪功能,默认为不开启。query.with.cipher.column: truesql.show: true              #SQL打印check.table.metadata.enabled: true            #是否在启动时检查分表元数据一致性,默认值: false
# proxy.frontend.flush.threshold:               # 对于单个大查询,每多少个网络包返回一次

注意事项:

(1)当你把注释的示例内容复制粘贴,然后用快捷键去掉‘#’注释符的时候,注意父子层的距离不要改变,比如下方父子层之间是两个空格。

props:max.connections.size.per.query: 1

(2) 在编写的时候不要用‘Tab’键拉开距离,应该使用空格键,否则启动的时候会报错。

小插曲

当你编写yml文件的时候,里面都会有这句话,一开始我以为还要在哪里引用这些要用的文件,后面才发现直接去掉注释编写就好,文件都是自动引用的。

If you want to configure orchestration, authorization and proxy properties, please refer to this file.

5、编写config-master_slave.yaml配置文件

schemaName: master_slave_dbdataSources:master:url: jdbc:mysql://127.0.0.1:3307/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50slave0:url: jdbc:mysql://127.0.0.1:3308/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50slave1:url: jdbc:mysql://127.0.0.1:3309/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50slave2:url: jdbc:mysql://127.0.0.1:3310/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50masterSlaveRule:name: ms_dsmasterDataSourceName: masterslaveDataSourceNames:- slave0- slave1- slave2

6、编写logback.xml日志记录文件

日志路径默认在启动方式start.bat下创建个logs文件夹,所以只要填写相对路径就好。下面设置的是按级别按天输出日志,基本符合常规需求。

<?xml version="1.0"?><configuration><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %highlight([%-5level] %logger{50} - %msg%n)</pattern><charset>UTF-8</charset></encoder></appender><!-- 系统正常日志文件 --><appender name="SYSTEM_INFO"  class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 过滤器,只打印INFO级别的日志 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名--><fileNamePattern>../logs/%d{yyyy-MM-dd}/info.%i.log</fileNamePattern><!--日志文件保留天数--><!-- <MaxHistory>15</MaxHistory> --><!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,命名日志文件,例如log-error-2013-12-21.0.log --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 追加方式记录日志 --><append>true</append><!-- 日志文件的格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%-5level] %logger{50} - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><!-- 系统警告日志文件,记录用户输入不符合规则的数据 --><appender name="SYSTEM_WARN"  class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 过滤器,只打印warn级别的日志 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>WARN</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名--><fileNamePattern>../logs/%d{yyyy-MM-dd}/warn.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>10MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 追加方式记录日志 --><append>true</append><!-- 日志文件的格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%-5level] %logger{50} - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><!-- 系统错误日志文件 --><appender name="SYSTEM_ERROR"  class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 过滤器,只打印ERROR级别的日志 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名--><fileNamePattern>../logs/%d{yyyy-MM-dd}/error.%i.log</fileNamePattern><!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,命名日志文件,例如log-error-2013-12-21.0.log --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><MaxFileSize>10MB</MaxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 追加方式记录日志 --><append>true</append><!-- 日志文件的格式 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%-5level] %logger{50} - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><logger name="system_error" additivity="false"><appender-ref ref="SYSTEM_ERROR"/></logger><!-- 默认纪录级别 --><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="SYSTEM_INFO" /><appender-ref ref="SYSTEM_WARN" /><appender-ref ref="SYSTEM_ERROR" /> </root></configuration>

7、启动sharding-proxy

在cmd命令窗口中cd到bin目录下,然后直接运行start.bat,默认是3307端口;当然你也可以指定端口,在后面加上参数即可,比如start.bat 3309即可指定连接端口为3309。然后观察cmd窗口,如果没报出异常的话表示启动成功。

8、客户端连接

这里推荐使用Navicat Premium 11 去连接,使用Navicat Premium 12的话你会发现很多奇怪的问题,下面是官网的建议和成功连接的图。至此,proxy服务端搭建好了,接下来是编写代码。

9、初始化表格

在master_slave_db库下新建一张area表用来测试,建好之后master,slave0,slave1,slave2的test库下也会自动创建。

CREATE TABLE `area`  (`id` bigint(0) UNSIGNED NOT NULL COMMENT 'id',`area_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '地区编号',`area_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '地区名称',`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '地区表(单库单表)' ROW_FORMAT = Dynamic;

10、pom.xml加入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><groupId>com.sharding-proxy.read-write</groupId><artifactId>sharding-proxy-read-write</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><name>sharding-proxy-read-write</name><description>shardingsphere之sharding-proxy读写分离</description><properties><java.version>1.8</java.version><mybatis-plus-generator.version>3.1.0</mybatis-plus-generator.version><mybatis-plus-extension.version>3.1.0</mybatis-plus-extension.version><mybatis-plus-boot-starter.version>3.1.0</mybatis-plus-boot-starter.version><mybatis-ehcache.version>1.0.0</mybatis-ehcache.version><org.apache.velocity.version>2.1</org.apache.velocity.version><druid-spring-boot-starter.version>1.1.18</druid-spring-boot-starter.version><hutool-core.version>4.6.4</hutool-core.version><guava.version>r05</guava.version></properties><dependencies><!-- springboot基本依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis-plus依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>${mybatis-plus-generator.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus-boot-starter.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-extension</artifactId><version>${mybatis-plus-extension.version}</version></dependency><!-- 集成echcache --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-ehcache</artifactId><version>${mybatis-ehcache.version}</version></dependency><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId></dependency><!-- 代码生成器模板 --><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>${org.apache.velocity.version}</version><scope>test</scope></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 熱部署 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional> <!-- 这个需要为 true 热部署才有效 --></dependency><!-- druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-spring-boot-starter.version}</version></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version><scope>runtime</scope></dependency><!-- bean工具 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>${hutool-core.version}</version></dependency><!-- 使用@ConfigurationProperties注解 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- 谷歌工具 --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>${guava.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

11、基础CRUD代码生成

通过示例代码的工具类可以快速生成基础的CRUD代码

 src/test/java/com/project/generator/MybatisGenerator.java

12、编写测试代码

@RestController
@RequestMapping("/area")
public class AreaController {@Autowiredprivate IAreaService areaService;@PostMapping("/save")public ResponseData<?> save() {List<Area> list = new ArrayList<Area>();list.add(new Area("110000", "北京市"));list.add(new Area("110101", "东城区"));list.add(new Area("110102", "西城区"));list.add(new Area("110106", "丰台区"));areaService.saveBatch(list);return ResponseData.out(CodeEnum.SUCCESS, null);}@GetMapping("/list")public ResponseData<?> list() {List<Area> aList = areaService.list();return ResponseData.out(CodeEnum.SUCCESS, aList);}@GetMapping("/update")public ResponseData<?> update(Long id) {Area area = new Area("1180000", "天津市");area.setId(id);areaService.updateById(area);return ResponseData.out(CodeEnum.SUCCESS, null);}@GetMapping("/delete")public ResponseData<?> delete(Long id) {areaService.removeById(id);return ResponseData.out(CodeEnum.SUCCESS, null);}
}

13、运行测试

通过发起请求同时观察日志文件你会发现:

(1)当执行插入操作时,打印如下SQL

[2020-05-07 12:10:23.545] [ShardingSphere-Command-5] [INFO ] ShardingSphere-SQL - Rule Type: master-slave
[2020-05-07 12:10:23.545] [ShardingSphere-Command-5] [INFO ] ShardingSphere-SQL - SQL: INSERT INTO area  ( id,
area_code,
area_name )  VALUES  ( 1258247784025628674,
'110000',
'新疆' ) ::: DataSources: master
[2020-05-07 12:10:23.584] [ShardingSphere-Command-6] [INFO ] ShardingSphere-SQL - Rule Type: master-slave
[2020-05-07 12:10:23.588] [ShardingSphere-Command-6] [INFO ] ShardingSphere-SQL - SQL: INSERT INTO area  ( id,
area_code,
area_name )  VALUES  ( 1258247784176623618,
'110101',
'乌鲁木齐' ) ::: DataSources: master
[2020-05-07 12:10:23.619] [ShardingSphere-Command-7] [INFO ] ShardingSphere-SQL - Rule Type: master-slave
[2020-05-07 12:10:23.619] [ShardingSphere-Command-7] [INFO ] ShardingSphere-SQL - SQL: INSERT INTO area  ( id,
area_code,
area_name )  VALUES  ( 1258247784180817921,
'110102',
'西藏' ) ::: DataSources: master
[2020-05-07 12:10:23.647] [ShardingSphere-Command-8] [INFO ] ShardingSphere-SQL - Rule Type: master-slave
[2020-05-07 12:10:23.647] [ShardingSphere-Command-8] [INFO ] ShardingSphere-SQL - SQL: INSERT INTO area  ( id,
area_code,
area_name )  VALUES  ( 1258247784189206529,
'110106',
'天台' ) ::: DataSources: master

(2)当执行查询操作时

[2020-05-08 11:54:18.768] [ShardingSphere-Command-4] [INFO ] ShardingSphere-SQL - Rule Type: master-slave
[2020-05-08 11:54:18.768] [ShardingSphere-Command-4] [INFO ] ShardingSphere-SQL - SQL: SELECT  id,area_code,area_name,create_time,update_time  FROM area ::: DataSources: slave1

出现异常参考

在整合的过程中可能由于框架之间的版本导致启动或者生成代码时报错,可参考下方提示,至于报错原因大家有空可以自行研究下。

报错1

报错信息:

CLIENT_PLUGIN_AUTH is required

或者

java.sql.SQLException: Unknown system variable 'query_cache_size'at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3978)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3914)at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2491)at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2449)at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1381)at com.mysql.jdbc.ConnectionImpl.loadServerVariables(ConnectionImpl.java:3797)at com.mysql.jdbc.ConnectionImpl.initializePropsFromServer(ConnectionImpl.java:3230)at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2243)at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2025)at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:778)at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)

解决方法:修改mysql的驱动版本,sirngboot2.1.6 对应的是mysql8.0.16版本,重写为5.1.6即可。

报错2

报错信息:

Caused by: java.sql.SQLFeatureNotSupportedException: nullat com.alibaba.druid.proxy.jdbc.ResultSetProxyImpl.getObject(ResultSetProxyImpl.java:1556)at com.alibaba.druid.pool.DruidPooledResultSet.getObject(DruidPooledResultSet.java:1771)at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38)at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28)at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:81)at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:521)at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:402)at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:354)at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:328)at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:301)

解决方法:修改mybatis-plus的版本为3.1.0即可。

结语

官网的文档比较详细和社区都是很活跃的,这些可以减少我们的学习成本,快速用于项目。如果在学习的过程中遇到问题可以多看看官方文档或者直接到github上面提issues,官方人员会很快给予答复的。

演示代码地址
Docker简介
CentOS7 安装Docker
CentOS系统Docker安装
Docker 安装 MySQL
基于Docker的Mysql主从复制搭建
MYSQL主从复制原理
连接 MySQL 报错:2059
启动slave时报错Slave failed to initialize relay log info structure from the repository
shardingsphere官网地址
Spring boot CLIENT_PLUGIN_AUTH is required
java.sql.SQLException: Unknown system variable ‘query_cache_size’

shardingsphere之sharding-proxy读写分离学习笔记相关推荐

  1. 视频教程-ShardingSphere:SpringBoot2+MybatisPlus+Swagger读写分离-Java

    ShardingSphere:SpringBoot2+MybatisPlus+Swagger读写分离 10多年互联网一线实战经验,现就职于大型知名互联网企业,架构师, 有丰富实战经验和企业面试经验:曾 ...

  2. 前后端分离学习笔记(5) ---[表单的增删改操作;以及为管理员上传头像]

    上一篇案例中也是查询到了表单的内容–>前后端分离学习笔记(4) -[路由嵌套, 查询表单显示] 文章目录 1.前端组件页面 添加管理员操作 修改管理员信息 删除管理员 为管理员上传头像 修改密码 ...

  3. SpringBoot + Sharding JDBC 读写分离、分库分表

    Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 ShardingSphere,20 ...

  4. Sharding Sphere 读写分离的配置

    #配置主从数据源,要基于MySQL主从架构. spring.shardingsphere.datasource.names=m0,s0spring.shardingsphere.datasource. ...

  5. MySQL Proxy 读写分离(实战总结)

    规划: 主mysql服务器:192.168.1.21 从mysql服务器: 192.168.1.22 mysql读写分离器:192.168.1.23 1.读写分离服务器上解压安装包,并添加对应用户,并 ...

  6. mysql proxy读写分离实现_使用mysql-proxy实现读写分离

    mysql-proxy本身并不能进行读写分离,要实现读写分离要依赖于lua,所以要先查看是否安装了lua,如果没有安装使用yum install安装上即可 ~]# rpm -q lua lua-5.1 ...

  7. 基于mysql主从同步的proxy读写分离

    mysql-proxy 简介 MySQL Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测.分析或改变它们的通信.它使用灵活,没有限制,常见的用途包括:负载 ...

  8. mysql oneproxy_利用oneproxy实现mysql读写分离搭建笔记

    功能: 1.具有SQL白名单(防SQL注入)及IP白名单功能的SQL防火墙软件 2.数据库故障切换 3.读写分离 4.分库分表 一.下载 oneproxy-rhel5-linux64-v6.0.0-g ...

  9. mysql读写分离 存储过程_基于maxscale的读写分离部署笔记

    使用maxscale搭建的读写分离架构,后期还可以再结合MHA做master的故障转移,这样业务层面上不需要做任何的改动即可. 基于connect方式的不要使用.从库延迟他还会继续分发请求过去,暂时不 ...

最新文章

  1. 吴恩达:如何建立一个成功的人工智能创业公司
  2. AI新方向: 科学家们暂停模仿“人脑”,公布了新路线图
  3. ado.net操作数据库常用方法集锦
  4. Ubuntu下常用命令
  5. python 预测算法_通过机器学习的线性回归算法预测股票走势(用Python实现)
  6. label-embedding在文本分类中的应用
  7. 计算机专业office,2011 级计算机专业 Office 办公软件期末考试.doc
  8. 题解 【国家集训队2011】数颜色
  9. org.eclipse.birt.report.exception.ViewerException: 没有可用的报表设计对象.
  10. [转载] 5.2 calendar--通用日期的相关函数(4)
  11. FocusPoint.js实现图片响应
  12. python selenium自动化框架_一文讲透!实现一个Python+Selenium的自动化测试框架如此简单!...
  13. Excel-财务函数1
  14. 正确的座机号码格式_电话号码的正确写法
  15. 飞鹤、贝因美、君乐宝们的难题:新生儿人口减少、育儿知识的变化
  16. ffmpeg java 实时视频流转码
  17. python tkinter界面可视化工具
  18. 2018年中考计算机考试成绩,2018年北京中考考试科目、时间及成绩公布通知
  19. 网络中常用的各种协议名称(中英文)和具体含义
  20. $NOIP 2018 PJ游记[ZJ]$

热门文章

  1. JavaScript:实现ROT13密码算法(附完整源码)
  2. 图片转文字的实用方法
  3. ipad投影到mac上_如何停止Mac和iPad上的来电
  4. TCP/IP协议栈 路由器 交换机
  5. 常见图片文件格式简析
  6. 新版鸟哥Linux私房菜资料
  7. 微PE安装系统 不显示U盘中镜像文件 的解决方法
  8. ie浏览器 “嗯...无法访问页面 尝试此操作...”的解决办法
  9. 用html语言编写笑脸,怎么使用HTML5中的Canvas绘制笑脸
  10. 13.请编一个函数void fun(int tt[M][N],int pp[N]),tt指向一个M行N列的二维数组,求出二维数组每列中最小元素,并依次放入pp所指一维数组中。