书接上回:数据库调优方案中数据库主从复制,如何实现读写分离
ShardingSphere 实现读写分离的方式是通过配置数据源的方式,使得应用程序可以在执行读操作和写操作时分别访问不同的数据库实例。这样可以将读取操作分发到多个从库(从服务器),从而提高读取性能,同时将写操作发送到主库(主服务器)以确保数据的一致性。
引入依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-version}</version>
</dependency>
配置
# 读写分离配置
spring:
shardingsphere:
datasource:
# 配置真实数据源
names: master,slave1,slave2
# 配置第 1 个数据源
master:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/sso
password: 123456
type: com.zaxxer.hikari.HikariDataSource
username: root
# 配置第 2 个数据源
slave1:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/sso_test
password: 123456
type: com.zaxxer.hikari.HikariDataSource
username: root
# 配置第 3 个数据源
slave2:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/slave_test
password: 123456
type: com.zaxxer.hikari.HikariDataSource
username: root
mode:
# 内存模式
type: Memory
# 打印sql
props:
sql-show: true
rules:
readwrite-splitting:
data-sources:
myds:
# 读数据源负载均衡算法名称
load-balancer-name: alg_round
props:
# 读数据源名称,多个从数据源用逗号分隔
read-data-source-names: slave1,slave2
# 写数据源名称
write-data-source-name: master
# 读写分离类型,如: Static,Dynamic
type: Static
load-balancers:
# 定义负载均衡算法:随机,轮询,权重
alg_random:
type: RANDOM
alg_round:
type: ROUND_ROBIN
alg_weight:
props:
slave1: 1
slave2: 2
type: WEIGHT
创建数据库表
由于主、从数据库里的数据是一样的,所以sso和sso_test都用下面代码创建sys_business表
CREATE TABLE `sys_business` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`avaliable` TINYINT ( 1 ) DEFAULT '1' COMMENT '是否可用#0:禁用#1:启用',
`name` VARCHAR ( 30 ) CHARACTER
SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '系统名称',
`permission` VARCHAR ( 30 ) CHARACTER
SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '权限字符',
`path` VARCHAR ( 100 ) CHARACTER
SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '路由地址',
`icon` VARCHAR ( 30 ) CHARACTER
SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '图表',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`delete_flag` TINYINT ( 1 ) DEFAULT '1' COMMENT '是否删除#1:未删除#0:已删除',
PRIMARY KEY ( `id` )
) ENGINE = INNODB AUTO_INCREMENT = 3 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;
编写实体类
@Data
@TableName("sys_business")
public class Sso {
private Long id;
private String name;
}
业务代码
mapper
public interface SsoMapper extends BaseMapper<Sso> {
}
service
public interface ISsoService extends IService<Sso> {
}
service实现类
@Service
public class ISsoServiceImpl extends ServiceImpl<SsoMapper, Sso> implements ISsoService {
}
测试
1、先在sso_test(从)读,后向sso(主)插(测试配置文件是否生效)
@Resource
private ISsoService iSsoService;
@RequestMapping("/slace_master")
public boolean masterTest(){
Sso sso = iSsoService.getById(1L);
System.out.println(sso.toString());
return iSsoService.save(sso);
}
当前从库中的数据:
主库此时还没有数据:
运行后:
先在从库中查出,然后向主库中写入,实现了数据的同步,说明集成生效了。
2、先插主库,后读从库(没有加事务)
因为sso_test没有对sso这个库的binlog日志进行监听,现在这两个库是没有同步关系的,写入sso后,不会同步到sso_test。
@RequestMapping("insert_and_read")
public boolean inAndRed(){
Sso sso =new Sso();
sso.setId(2L);
sso.setName("TestName1");
boolean save = iSsoService.save(sso);
Sso byId = iSsoService.getById(2L);
System.out.println(byId);
return save;
}
执行后主库中的数据:
执行后从库中的数据:
打印结果:
在2中的方法上加事务@Transactional注解(会强制读取刚执行完写入的库也就是主库)
@RequestMapping("insert_and_read")
@Transactional
public boolean inAndRed(){
Sso sso =new Sso();
sso.setId(2L);
sso.setName("TestName1");
boolean save = iSsoService.save(sso);
Sso byId = iSsoService.getById(2L);
System.out.println(byId);
return save;
}