# Sharding **Repository Path**: tataben/Sharding ## Basic Information - **Project Name**: Sharding - **Description**: 整合Spring Boot 2、ShardingSphere 3、Druid、Mybatis框架实现分库、分表及读写分离的Demo - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2019-10-23 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Sharding #### 介绍 实现分库、分表及读写分离的Demo #### 软件架构 整合Spring Boot 2、Sharding Sphere 3、Druid、Mybatis框架 #### 参考 1. https://shardingsphere.apache.org/document/legacy/3.x/document/cn/manual/ 2. https://www.fangzhipeng.com/mysql.html 3. CentOS7 下载 http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1908.iso #### 步骤 ##### 安装虚拟机 1. 用 VM 准备3台 CentOS7 系统虚拟机(最小安装) * master: 192.168.192.131 (主) * slave1: 192.168.192.129 (从1) * slave2: 192.168.192.132 (从2) 2. 安装网络工具 * 执行 `yum install net-tools` 安装 3. 如果安装后不能上网,修改 ONBOOT 改为 yes 后重新启动(`shutdown -r now`),如: * 执行 `ip add` 查看文件名称 * 执行 `vi /etc/sysconfig/network-scripts/ifcfg-ens33` 修改为以下内容保存退出 ``` TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no #BOOTPROTO=dhcp DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=ens33 UUID=065100c4-434c-4a05-afcf-b36aff593d17 DEVICE=ens33 ONBOOT=yes BOOTPROTO=static IPADDR=静态IP(这里有三台IP 192.168.192.131,192.168.192.129,192.168.192.132) NETMASK=255.255.255.0 GATEWAY=虚拟机网关,可在 `编辑` -> `虚拟网络编辑器中查看` DNS1=61.139.2.69 DNS2=8.8.8.8 ``` * 执行 `shutdown -r now` 重新启动, 或执行 `systemctl restart network` 使用网络配置生效 4. 关闭防火墙,此处方便学习直接关掉即可 * 执行 `systemctl stop firewalld` 关闭 * 执行 `systemctl disable firewalld` 禁用开机启动 ##### 安装数据库 1. 安装 Mysql5.7 * 执行 `wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm` 下载Mysql yum源 * 执行 `yum localinstall mysql57-community-release-el7-11.noarch.rpm` 安装刚下载的yum源 * 执行 `yum repolist enabled | grep "mysql.*-community.*"` 检测yum源是否安装成功 * 执行 `yum install -y mysql-community-server` 安装Mysql * 执行 `systemctl start mysqld` 启动Mysql * 执行 `systemctl status mysqld` 查看Mysql状态 * 执行 `systemctl enable mysqld` 设置开机启动 2. 修改 Mysql 登录密码 * 执行 `grep 'temporary password' /var/log/mysqld.log` 查看首次登录密码 * 执行 `mysql -uroot -p` 登录Mysql * 执行 `ALTER USER 'root'@'localhost' IDENTIFIED BY '你的数据库密码';` 修改密码 3. 允许远程登录(生产环境不建议用root账户) * 执行 `use mysql;` * 执行 `UPDATE user SET Host='%' WHERE User='root';` 允许root账号远程登录 * 执行 `flush privileges;` 使修改生效 4. 开启日志(非必须,生产环境不建议开启) * 执行 `show variables like '%general_log%';` 查看日志目录 * 执行 `set global general_log=on;` 开启sql语句的日志 5. 创建据库 * 执行如下命令创建两数据库,分别为 cloud 和 cloud1 ``` CREATE DATABASE `cloud` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE DATABASE `cloud1` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` ##### 主从配置 1. 配置主数据库(master) * 修改 master 配置文件,如: ``` # server-id给数据库服务的唯一标识 server-id=1 # log-bin设置此参数表示启用binlog功能,并指定路径名称 log-bin=/var/lib/mysql/mysql-bin sync_binlog=0 # 设置日志的过期天数 expire_logs_days=7 # 需要同步的数据库 binlog-do-db=cloud binlog-do-db=cloud1 # 同步的时候忽略的数据库 binlog-ignore-db=sys binlog-ignore-db=mysql binlog-ignore-db=information_schema binlog-ignore-db=performance_schema ``` * 执行 `systemctl restart mysqld` 重启数据库 * 执行 `mysql -uroot -p` 登录数据库 * 赋予从库权限账号,允许用户在主库上读取日志(这里都是用的 root 账号,生产环境不推荐)) ``` grant FILE on *.* to 'root'@'192.168.192.132' identified by '密码'; grant replication slave on *.* to 'root'@'192.168.192.132' identified by '密码'; flush privileges; grant FILE on *.* to 'root'@'192.168.192.129' identified by '密码'; grant replication slave on *.* to 'root'@'192.168.192.129' identified by '密码'; flush privileges; ``` * 执行 `systemctl restart mysqld` 重启数据库 * 执行 `mysql -uroot -p` 登录数据库 * 执行 `show master status;` 查看主库信息 2. 配置从数据库(slave) * 执行 `vi /etc/my.cnf` 修改配置文件,添加以下内容: ``` log-bin=mysql-bin # 两个从库的server-id不一样,需要唯一 server-id=3 binlog-ignore-db=information_schema binlog-ignore-db=sys binlog-ignore-db=mysql replicate-do-db=cloud replicate-do-db=cloud1 replicate-ignore-db=mysql log-slave-updates slave-skip-errors=all slave-net-timeout=60 ``` * 执行 `systemctl restart mysqld` 重启数据库 * 执行 `mysql -uroot -p` 登录数据库 * 配置 File 及 Position 值,File 及 Position 的值在 master 上执行 `show master status;` 获取,配置如下: ``` stop slave; change master to master_host='192.168.192.131',master_user='root',master_password='密码',master_log_file='File值', master_log_pos=Position值; start slave; ``` * 执行 `show slave status;` 查看从库信息 * 如果配置 File 及 Position 值出错,可执行下命令清空配置,再重新配置,如下:(如果未出错,则可忽略) ``` stop slave; reset slave all; ``` ##### Spring Boot + Sharding JDBC + Druid + Mybatis 项目 1. 搭建(使用的IDE为 VS Code) * 使用 VS Code 创建 Spring Boot 项目,名为Sharding * 修改 pom.xml 配置文件,添加依赖项,见 pom.xml 文件 * 在 resources 目录添加 druid.properties 及 sharding.properties 配置文件 * 在 App.java 文件 引入上一步骤添加的两配置文件,见 APP.java 文件 * 在 application.properties 加入 spring.main.allow-bean-definition-overriding=true 配置,允许覆盖同名的 Bean * 在 druid.properties 配置 Druid 相关配置,这里不配置 url、driver、username 及 password 等参数,详情见 druid.properties 文件 2. 实现 读写分离 * 在 master 数据库中执行以下命令创建表: ``` USE `cloud`; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; ``` * 在 sharding.properties 文件加入以下内容:(具体配置见sharding.properties) ``` # 开启日志 sharding.jdbc.config.props.sql.show=true # 数据库名称 sharding.jdbc.datasource.names=marster,slave1,slave2 # 主数据库 datasource sharding.jdbc.datasource.marster1.type=com.alibaba.druid.pool.DruidDataSource sharding.jdbc.datasource.marster1.driver-class-name=com.mysql.cj.jdbc.Driver sharding.jdbc.datasource.marster1.url=jdbc:mysql://192.168.192.131:3306/cloud sharding.jdbc.datasource.marster1.username=root sharding.jdbc.datasource.marster1.password=数据库登录密码 # 从1数据库 datasource sharding.jdbc.datasource.marster1.type=com.alibaba.druid.pool.DruidDataSource sharding.jdbc.datasource.marster1.driver-class-name=com.mysql.cj.jdbc.Driver sharding.jdbc.datasource.marster1.url=jdbc:mysql://192.168.192.129:3306/cloud sharding.jdbc.datasource.marster1.username=root sharding.jdbc.datasource.marster1.password=数据库登录密码 # 从2数据库 datasource sharding.jdbc.datasource.marster1.type=com.alibaba.druid.pool.DruidDataSource sharding.jdbc.datasource.marster1.driver-class-name=com.mysql.cj.jdbc.Driver sharding.jdbc.datasource.marster1.url=jdbc:mysql://192.168.192.132:3306/cloud sharding.jdbc.datasource.marster1.username=root sharding.jdbc.datasource.marster1.password=数据库登录密码 # 读写分离(单独) sharding.jdbc.config.masterslave.name=ms sharding.jdbc.config.masterslave.master-data-source-name=marster sharding.jdbc.config.masterslave.slave-data-source-names=slave1,slave2 # 此处 ROUND_ROBIN 必为大写,小写会出错 sharding.jdbc.config.masterslave.load-balance-algorithm-type=ROUND_ROBIN ``` * 测试逻辑编写见 UserController.java 文件 3. 实现 分表 + 读写分离 * 在 master 数据库中执行以下命令创建表: ``` USE `cloud`; DROP TABLE IF EXISTS `user0`; CREATE TABLE `user0` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user1`; CREATE TABLE `user1` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user2`; CREATE TABLE `user2` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user3`; CREATE TABLE `user3` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; ``` * 在读写分离的配置基础上,将读写分离的配置替换为以下内容:(具体配置见sharding.properties) ``` # 分表+读写分离 ## 分表 sharding.jdbc.config.sharding.tables.user.actual-data-nodes=ds0.user$->{0..3} sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user$->{id % 4} ## 读写分离 sharding.jdbc.config.sharding.master-slave-rules.ds0.master-data-source-name=marster sharding.jdbc.config.sharding.master-slave-rules.ds0.slave-data-source-names=slave1,slave2 ``` * 测试逻辑编写见 UserController.java 文件 4. 实现 分库 + 分表 + 读写分离 * 在 master 数据库中执行以下命令创建表: ``` USE `cloud`; DROP TABLE IF EXISTS `user0`; CREATE TABLE `user0` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user1`; CREATE TABLE `user1` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user2`; CREATE TABLE `user2` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user3`; CREATE TABLE `user3` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user4`; CREATE TABLE `user4` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; USE `cloud1`; DROP TABLE IF EXISTS `user0`; CREATE TABLE `user0` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user1`; CREATE TABLE `user1` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user2`; CREATE TABLE `user2` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user3`; CREATE TABLE `user3` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; DROP TABLE IF EXISTS `user4`; CREATE TABLE `user4` ( `id` int(12) NOT NULL AUTO_INCREMENT, `username` varchar(12) NOT NULL, `password` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx-username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; ``` * 更改 sharding.properties 文件内容,具体配置见 sharding.properties * 测试逻辑编写见 UserController.java 文件