机器名称 | IP | 角色 | 权限 |
---|---|---|---|
Mysql_Master1 | 172.16.94.5 | 数据库 Master | 可读写、主库 |
Mysql_Slave1 | 172.16.94.6 | 数据库 Slave | 只读、从库 |
Mysql_Slave2 | 172.16.94.10 | 数据库 Slave | 只读、从库 |
Mysql_Master11 | 172.16.94.17 | 数据库 Master11 | 可读写、主库 |
Mysql_Slave11 | 172.16.94.18 | 数据库 Slave11 | 只读、从库 |
Mysql_Slave22 | 172.16.94.19 | 数据库 Slave22 | 只读、从库 |
MySQL 主从搭建 一主二从
主库配置/etc/my.cnf
#bin_log 配置
log_bin=mysql-bin
server-id=1
sync-binlog=1
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
#relay_log 配置
relay_log=mysql-relay-bin
log_slave_updates=1
relay_log_purge=0
两台从库配置/etc/my.cnf
#bin_log 配置
log_bin=mysql-bin
#服务器 ID,从库 2、3
server-id=2
sync-binlog=1
binlog-ignore-db=information_schema
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
#relay_log 配置
relay_log=mysql-relay-bin
log_slave_updates=1
relay_log_purge=0
read_only=1
三台分别重启服务
systemctl restart mysqld
主库开启权限
#进入mysql
grant replication slave on *.* to 'root'@'%' identified by 'root';
grant all privileges on *.* to 'root'@'%' identified by 'root';
flush privileges;
grant replication slave on *.* to 'mha'@'%' identified by '123123';
grant all privileges on *.* to 'mha'@'%' identified by '123123';
flush privileges;
两台从库建立主从关系
#查看是否以前有配置信息,若有则去除掉
show slave status;
#stop slave;
#reset slave all;
#在主库查看binlog状态
#show master status \G;
#从库设置主库信息
change master to master_host='172.16.94.5',master_port=3306,master_user='root',master_password='root',
master_log_file='mysql-bin.000014',master_log_pos=154;
#开启从库
start slave;
#再次查看从库配置信息
show slave status \G;
分别复制主库和两个从库
虚拟机直接克隆
修改主库 2 配置/etc/my.cnf
server-id=11
修改从库 11、22 配置/etc/my.cnf
vim /etc/my.cnf
server-id=12
server-id=13
查找下 auto.cnf 文件的位置,全部修改
find / -name "auto.cnf"
vim /var/lib/mysql/auto.cnf
[auto]
server-uuid=356fc1ff-e339-11eb-bbea-000c29c18311
查看主库 22 的状态
mysql> show master status \G;
*************************** 1. row ***************************
File: mysql-bin.000015
Position: 154
Binlog_Do_DB:
Binlog_Ignore_DB: information_schema,performance_schema,sys
Executed_Gtid_Set:
1 row in set (0.00 sec)
修改从库 22 和从库 33 的主库
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
mysql> reset slave all;
Query OK, 0 rows affected (0.01 sec)
mysql> change master to master_host='172.16.94.17',master_port=3306,master_user='root',master_password='root',
-> master_log_file='mysql-bin.000015',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.16.94.17
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000015
Read_Master_Log_Pos: 154
Relay_Log_File: mysql-relay2-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000015
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
1 row in set (0.00 sec)
重启下这三台服务
systemctl restart mysqld
初始化数据
主库分别创建 lane3、lane5 和 c_order 表
➜ ~ mysql -uroot -proot
mysql> create database lane5;
Query OK, 1 row affected (0.00 sec)
mysql> use lane5;
Database changed
mysql> CREATE TABLE `c_order` (
-> `id` BIGINT ( 20 ) NOT NULL AUTO_INCREMENT,
-> `is_del` bit ( 1 ) NOT NULL DEFAULT 0 COMMENT '是否被删除',
-> `user_id` INT ( 11 ) NOT NULL COMMENT '⽤户id',
-> `company_id` INT ( 11 ) NOT NULL COMMENT '公司id',
-> `publish_user_id` INT ( 11 ) NOT NULL COMMENT 'B端⽤户id',
-> `position_id` INT ( 11 ) NOT NULL COMMENT '职位ID',
-> `resume_type` INT ( 2 ) NOT NULL DEFAULT 0 COMMENT '简历类型:0附件 1在线',
-> `status` VARCHAR ( 256 ) NOT NULL COMMENT '投递状态 投递状态 WAIT-待处理 AUTO_FILTER-⾃动过滤 PREPARE_CONTACT-待沟通 REFUSE-拒绝 ARRANGE_INTERVIEW-通知⾯试',
-> `create_time` datetime NOT NULL COMMENT '创建时间',
-> `update_time` datetime NOT NULL COMMENT '处理时间',
-> PRIMARY KEY ( `id` ),
-> KEY `index_userId_positionId` ( `user_id`, `position_id` ),
-> KEY `idx_userId_operateTime` ( `user_id`, `update_time` )
-> ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
Query OK, 0 rows affected (0.01 sec)
mysql>
查看第二组从库是否 有 lane5 和 c_order 表
➜ ~ mysql -uroot -proot
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| lane1 |
| lane2 |
| lane5 |
| lanebin |
| mysql |
| performance_schema |
| sys |
+--------------------+
8 rows in set (0.01 sec)
mysql> use lane5
mysql> show tables;
+-----------------+
| Tables_in_lane5 |
+-----------------+
| c_order |
+-----------------+
1 row in set (0.00 sec)
mysql>
查看第一组从库是否 有 lane3 和 c_order 表
mysql> use lane3
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------+
| Tables_in_lane3 |
+-----------------+
| c_order |
+-----------------+
1 row in set (0.00 sec)
mysql>
开始创建项目
创建 maven 项目 mysql-work
添加依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.galaxy</groupId>
<artifactId>mysql-work</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.compile.sourceEncoding>UTF-8</project.compile.sourceEncoding>
<shardingsphere.version>4.1.0</shardingsphere.version>
<springboot.version>2.2.9.RELEASE</springboot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<testSource>11</testSource>
<testTarget>11</testTarget>
</configuration>
</plugin>
</plugins>
</build>
</project>
entity
package com.galaxy.entity;
import javax.persistence.*;
import java.util.Date;
/**
* @author lane
* @date 2021年07月27日 下午7:12
*/
@Entity
@Table(name = "c_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "is_del")
private Boolean del;
@Column(name = "user_id")
private Integer userId;
@Column(name = "company_id")
private Integer companyId;
@Column(name = "publish_user_id")
private Integer publishUserId;
@Column(name = "position_id")
private Integer positionId;
@Column(name = "resume_type")
private Integer resumeType;
@Column(name = "status")
private String status;
@Column(name = "create_time")
private Date createTime;
@Column(name = "update_time")
private Date updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Boolean getDel() {
return del;
}
public void setDel(Boolean del) {
this.del = del;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getCompanyId() {
return companyId;
}
public void setCompanyId(Integer companyId) {
this.companyId = companyId;
}
public Integer getPublishUserId() {
return publishUserId;
}
public void setPublishUserId(Integer publishUserId) {
this.publishUserId = publishUserId;
}
public Integer getPositionId() {
return positionId;
}
public void setPositionId(Integer positionId) {
this.positionId = positionId;
}
public Integer getResumeType() {
return resumeType;
}
public void setResumeType(Integer resumeType) {
this.resumeType = resumeType;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", del=" + del +
", userId=" + userId +
", companyId=" + companyId +
", publishUserId=" + publishUserId +
", positionId=" + positionId +
", resumeType=" + resumeType +
", status='" + status + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
repository
package com.galaxy.repository;
import com.galaxy.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author lane
* @date 2021年07月27日 下午7:14
*/
public interface OrderRepository extends JpaRepository<Order,Long> {
}
application.properties
spring.shardingsphere.datasource.names=master-0,slave-1,slave-2,master-1,slave-3,slave-4
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.datasource.master-0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master-0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master-0.jdbc-url=jdbc:mysql://172.16.94.5:3306/lane3?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.master-0.username=root
spring.shardingsphere.datasource.master-0.password=root
spring.shardingsphere.datasource.slave-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave-1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave-1.jdbc-url=jdbc:mysql://172.16.94.6:3306/lane3?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.slave-1.username=root
spring.shardingsphere.datasource.slave-1.password=root
spring.shardingsphere.datasource.slave-2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave-2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave-2.jdbc-url=jdbc:mysql://172.16.94.10:3306/lane3?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.slave-2.username=root
spring.shardingsphere.datasource.slave-2.password=root
spring.shardingsphere.datasource.master-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master-1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master-1.jdbc-url=jdbc:mysql://172.16.94.17:3306/lane5?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.master-1.username=root
spring.shardingsphere.datasource.master-1.password=root
spring.shardingsphere.datasource.slave-3.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave-3.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave-3.jdbc-url=jdbc:mysql://172.16.94.18:3306/lane5?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.slave-3.username=root
spring.shardingsphere.datasource.slave-3.password=root
spring.shardingsphere.datasource.slave-4.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave-4.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave-4.jdbc-url=jdbc:mysql://172.16.94.19:3306/lane5?useUnicode=true&useSSL=false
spring.shardingsphere.datasource.slave-4.username=root
spring.shardingsphere.datasource.slave-4.password=root
spring.shardingsphere.sharding.tables.c_order.database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.c_order.database-strategy.inline.algorithm-expression=master-$->{user_id % 2}
spring.shardingsphere.sharding.tables.c_order.actual-data-nodes=master-$->{0..1}.c_order
spring.shardingsphere.sharding.tables.c_order.key-generator.column=id
spring.shardingsphere.sharding.tables.c_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.master-slave-rules.master-0.master-data-source-name=master-0
spring.shardingsphere.sharding.master-slave-rules.master-0.slave-data-source-names=slave-1,slave-2
#spring.shardingsphere.masterslave.load-balance-algorithm-type=ROUND_ROBIN
spring.shardingsphere.sharding.master-slave-rules.master-1.master-data-source-name=master-1
spring.shardingsphere.sharding.master-slave-rules.master-1.slave-data-source-names=slave-3,slave-4
test
/**
* @author lane
* @date 2021年07月27日 下午7:16
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShardingBootRunApplication.class)
public class ShardingTest {
@Autowired
private OrderRepository orderRepository;
@org.junit.Test
public void test(){
for (int idx = 0; idx < 4; ++idx) {
Order order = new Order();
order.setCompanyId(1);
order.setCreateTime(new Date());
order.setDel(false);
order.setPositionId(1);
order.setStatus("WAITING");
order.setPublishUserId(1);
order.setResumeType(1);
order.setUpdateTime(new Date());
order.setUserId(idx);
orderRepository.save(order);
}
}
@Test
public void testSlave(){
List<Order> all = orderRepository.findAll();
System.out.println(all);
}
}
测试分库分表和主从同步结果
通过 Master1 和 Master11 的查询结果可以看出分库成功
通过 Slave1 和 Slave11 可以看到主从同步 OK
master1
mysql> select * from c_order \G;
*************************** 1. row ***************************
id: 626865956605394944
is_del:
user_id: 0
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:30
update_time: 2021-07-27 19:41:30
*************************** 2. row ***************************
id: 626865957251317760
is_del:
user_id: 2
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
2 rows in set (0.00 sec)
slave1
mysql> use lane3
mysql> select * from c_order \G;
*************************** 1. row ***************************
id: 626865956605394944
is_del:
user_id: 0
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:30
update_time: 2021-07-27 19:41:30
*************************** 2. row ***************************
id: 626865957251317760
is_del:
user_id: 2
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
2 rows in set (0.00 sec)
master11
mysql> select * from c_order \G;
*************************** 1. row ***************************
id: 626865957129682945
is_del:
user_id: 1
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
*************************** 2. row ***************************
id: 626865957284872193
is_del:
user_id: 3
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
2 rows in set (0.00 sec)
slave11
mysql> use lane5;
mysql> select * from c_order\G;
*************************** 1. row ***************************
id: 626865957129682945
is_del:
user_id: 1
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
*************************** 2. row ***************************
id: 626865957284872193
is_del:
user_id: 3
company_id: 1
publish_user_id: 1
position_id: 1
resume_type: 1
status: WAITING
create_time: 2021-07-27 19:41:31
update_time: 2021-07-27 19:41:31
2 rows in set (0.00 sec)
测试读写分离结果
分别修改下 slave1 和 slave11 中 c_order 表的数据
#slave1
update c_order set status ='slave1';
#slave11
update c_order set status ='slave11';
查看读取的数据,可以看到读取到的是从库中 c_order 的数据,成功实现读写分离
[Order{id=626865956605394944, del=false, userId=0, companyId=1, publishUserId=1, positionId=1, resumeType=1, status='slave1',
createTime=2021-07-27 19:41:30.0, updateTime=2021-07-27 19:41:30.0},
Order{id=626865957251317760, del=false, userId=2, companyId=1, publishUserId=1, positionId=1, resumeType=1, status='slave1',
createTime=2021-07-27 19:41:31.0, updateTime=2021-07-27 19:41:31.0},
Order{id=626865957129682945, del=false, userId=1, companyId=1, publishUserId=1, positionId=1, resumeType=1, status='slave11',
createTime=2021-07-27 19:41:31.0, updateTime=2021-07-27 19:41:31.0},
Order{id=626865957284872193, del=false, userId=3, companyId=1, publishUserId=1, positionId=1, resumeType=1, status='slave11',
createTime=2021-07-27 19:41:31.0, updateTime=2021-07-27 19:41:31.0}]
2