03ShardingSphere-JDBC读写分离

背景

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

与将数据根据分片键打散至各个数据节点的水平分片不同,读写分离则是根据 SQL 语义的分析,将读操作和写操作分别路由至主库与从库。

背景

读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读写分离联合使用,能够更加有效的提升系统性能。

许多系统通过采用主从数据库架构的配置来提高整个系统的吞吐量,但是主从的配置也给业务的使用带来了一定的复杂性。接入 ShardingSphere,可以利用读写分离功能管理主从数据库,实现透明化的读写分离功能,让用户像使用一个数据库一样使用主从架构的数据库。

1、创建SpringBoot程序

https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/yaml-config/jdbc-driver/spring-boot/

1.1、创建项目

项目类型:Spring Initializr

SpringBoot脚手架:http://start.aliyun.com

项目名:sharding-jdbc-demo

image-20230808212758491

SpringBoot版本:2.3.12.RELEASE

image-20230808212822422

1.2、添加依赖

    <properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.12.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core</artifactId><version>5.4.0</version></dependency><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.33</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies>

升级到 ShardingSphere 5.3.0 或更高的版本,以Spring Boot项目举例原有相关的依赖将会失效:

<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>${shardingsphere.version}</version>
</dependency>

调整为:

<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core</artifactId><version>${shardingsphere.version}</version>
</dependency>

1.3、创建实体类

package com.dongguo.shardingjdbc.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@TableName("t_user")
@Data
public class User {@TableId(type = IdType.AUTO)private Long id;private String uname;
}

1.4、创建Mapper

package com.dongguo.shardingjdbc.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dongguo.shardingjdbc.entity.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<User> {
}

1.5、配置读写分离

application.yml:

# 应用名称
spring:application:name: sharding-jdbc-demoprofiles:active: devdatasource:# 配置 DataSource Driverdriver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver# 指定 YAML 配置文件url: jdbc:shardingsphere:classpath:shardingsphere-readwrite.yaml

shardingsphere-readwrite.yaml

#模式配置
mode:type: Standalone
# 数据源配置
dataSources:master:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3306/db_userusername: rootpassword: 123456slave1:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3307/db_userusername: rootpassword: 123456slave2:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3308/db_userusername: rootpassword: 123456
#规则配置
rules:
- !READWRITE_SPLITTINGdataSources:myds:writeDataSourceName: masterreadDataSourceNames:- slave1- slave2loadBalancerName: alg_round#算法配置loadBalancers:alg_round:type: ROUND_ROBINalg_random:type: RANDOMalg_weight:type: WEIGHTprops:slave1: 1slave2: 2
#属性配置
props:sql-show: true

从ShardingSphere 5.x版本开始,支持使用jdbc:shardingsphere:作为DataSource URL的前缀,来引入ShardingSphere的配置。这个特性被称为Spring ShardingSphere的可插拔数据源特性,可以通过可插拔的方式,将ShardingSphere数据源无缝集成到Spring应用中,从而实现自动化和透明化的分库分表。

模式配置

mode (?): # 不配置则默认单机模式type: # 运行模式类型。可选配置:Standalone、Clusterrepository (?): # 持久化仓库配置

ShardingSphere 5.x版本开始支持3种模式,包括Memory内存、Standalone 独立和Cluster集群模式

ShardingSphere 5.4 取消了 memory 模式配置,原因是在该模式下,数据全部存储在内存中,当数据量过大时会导致内存不足,影响系统性能。为了解决这个问题,ShardingSphere 推荐使用基于数据库的标准模式配置来代替 memory 模式,这样可以避免内存不足的问题,同时也可以更好地保证数据的安全性和一致性。如果您需要在 ShardingSphere 5.4 中使用 memory 模式配置,可以考虑使用之前的版本或者自定义实现。

数据源配置

dataSources: # 数据源配置,可配置多个 <data-source-name><data_source_name>: # 数据源名称dataSourceClassName: # 数据源完整类名driverClassName: # 数据库驱动类名,以数据库连接池自身配置为准jdbcUrl: # 数据库 URL 连接,以数据库连接池自身配置为准username: # 数据库用户名,以数据库连接池自身配置为准password: # 数据库密码,以数据库连接池自身配置为准# ... 数据库连接池的其它属性

示例的数据库驱动为 MySQL,连接池为 HikariCP,可以更换为其他数据库驱动和连接池。当使用 ShardingSphere-JDBC 时,JDBC 池的属性名取决于各自 JDBC 池自己的定义,并不由 ShardingSphere 硬定义,相关的处理可以参考类org.apache.shardingsphere.infra.datasource.pool.creator.DataSourcePoolCreator。例如对于 Alibaba Druid 1.2.9 而言,使用 url 代替如下示例中的 jdbcUrl 是预期行为。

如:

datasource:# 主数据源master:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.122.150:3306/db_userusername: rootpassword: 123456# 从数据源slave:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.122.150:3306/db_userusername: rootpassword: 123456

规则配置-读写分离

rules:
- !READWRITE_SPLITTINGdataSources:<data_source_name> (+): # 读写分离逻辑数据源名称writeDataSourceName: # 写库数据源名称readDataSourceNames: # 读库数据源名称,多个从数据源用逗号分隔transactionalReadQueryStrategy (?): # 事务内读请求的路由策略,可选值:PRIMARY(路由至主库)、FIXED(同一事务内路由至固定数据源)、DYNAMIC(同一事务内路由至非固定数据源)。默认值:DYNAMICloadBalancerName: # 负载均衡算法名称# 负载均衡算法配置loadBalancers:<load_balancer_name> (+): # 负载均衡算法名称type: # 负载均衡算法类型props: # 负载均衡算法属性配置# ...

注意这里官网给出的参数解释中write_data_source_name、read_data_source_names有误

配置项使用了_分隔命名,但是会运行会显示解析错误,因此需要改为驼峰命名

image-20230809203503900

在负载均衡算法的讲解中的参数是正确的:

https://shardingsphere.apache.org/document/current/cn/user-manual/common-config/builtin-algorithm/load-balance/

image-20230809203436125

算法配置-读写分离负载均衡算法

loadBalancers:# loadBalancerName 由用户指定,需要和读写分离规则中的 loadBalancerName 属性一致<loadBalancerName>:# type 和 props,请参考读写分离负载均衡内置算法:https://shardingsphere.apache.org/document/current/cn/user-manual/common-config/builtin-algorithm/load-balance/type: xxxprops:xxx: xxx
配置标识详细 说明全限定类名
ROUND_ROBIN基于轮询的读库负载均衡算法org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.RoundRobinReadQueryLoadBalanceAlgorithm
RANDOM基于随机的读库负载均衡算法org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.RandomReadQueryLoadBalanceAlgorithm
WEIGHT基于权重的读库负载均衡算法org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.WeightReadQueryLoadBalanceAlgorithm

通用配置-属性配置

props:sql-show: true
名称数据类型说明默认值
sql-showboolean是否在日志中打印 SQL 打印 SQL 可以帮助开发者快速定位系统问题。日志内容包含:逻辑 SQL,真实 SQL 和 SQL 解析结果。 如果开启配置,日志将使用 Topic ShardingSphere-SQL,日志级别是 INFOfalse

yaml配置参考

https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/yaml-config/

2、测试

2.1、读写分离测试

写入

package com.dongguo.shardingjdbc;import com.dongguo.shardingjdbc.entity.User;
import com.dongguo.shardingjdbc.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class ReadwriteTest {@Autowiredprivate UserMapper userMapper;/*** 写入数据的测试*/@Testpublic void testInsert(){User user = new User();user.setUname("张三丰");userMapper.insert(user);}
}

执行这个测试类,运行结果;

2023-08-09 13:12:51.670  INFO 38604 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO t_user  ( uname )  VALUES  ( ? )
2023-08-09 13:12:51.670  INFO 38604 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: INSERT INTO t_user  ( uname )  VALUES  ( ? ) ::: [张三丰]

查看数据库

master

image-20230809131452742

slave1

image-20230809131516558

slave2

image-20230809131532121

查询

    @Testpublic void testSelect(){User user = userMapper.selectById(1);System.out.println(user);}

运行结果

2023-08-09 21:43:44.232  INFO 27836 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT id,uname FROM t_user WHERE id=? 
2023-08-09 21:43:44.232  INFO 27836 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT id,uname FROM t_user WHERE id=?  ::: [1]
User(id=1, uname=zhang3)

这里可以看到在master写入,在slave读取

为了更加确认我们可以在同一个方法中执行写入和读取操作

    @Testpublic void testReadwrite(){User user = new User();user.setUname("张三");userMapper.insert(user);List<User> userList = userMapper.selectList(null);userList.forEach(System.out::println);}

运行结果

2023-08-09 22:04:09.897  INFO 37108 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO t_user  ( uname )  VALUES  ( ? )
2023-08-09 22:04:09.897  INFO 37108 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: INSERT INTO t_user  ( uname )  VALUES  ( ? ) ::: [张三]
2023-08-09 22:04:10.032  INFO 37108 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-09 22:04:10.032  INFO 37108 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)
User(id=6, uname=张三)

master负责写,slave负责读,实现读写分离。

报错

java.lang.NoSuchMethodError: org.yaml.snakeyaml.LoaderOptions.setCodePointLimit(I)V

shardingsphere5.4.0与snakeyaml1.26不兼容

image-20230809195925312

尝试升级版本,正常启动

        <dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.33</version></dependency>

具体原因

https://github.com/apache/shardingsphere/issues/21476

在这里插入图片描述

2.2、事务测试

为了保证主从库间的事务一致性,避免跨服务的分布式事务,ShardingSphere-JDBC的主从模型中,事务中的数据读写均用主库

  • 不添加@Transactional:insert对主库操作,select对从库操作

  • shardingsphere5.4.0版本读写分离添加@Transactional由规则transactionalReadQueryStrategy 决定

    事务内读请求的路由策略,可选值:PRIMARY(路由至主库)、FIXED(同一事务内路由至固定数据源)、DYNAMIC(同一事务内路由至非固定数据源)。默认值:

  • **注意:**在JUnit环境下的@Transactional注解,默认情况下就会对事务进行回滚(即使在没加注解@Rollback,也会对事务回滚)

在该测试方法上加上@Transactional开启事务

    @Transactional@Testpublic void testReadwrite(){User user = new User();user.setUname("张三");userMapper.insert(user);List<User> userList = userMapper.selectList(null);userList.forEach(System.out::println);}

运行结果

2023-08-09 22:09:26.323  INFO 12836 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@33bc72d1 testClass = ReadwriteTest, testInstance = com.dongguo.shardingjdbc.ReadwriteTest@2917abdb, testMethod = testReadwrite@ReadwriteTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@1a75e76a testClass = ReadwriteTest, locations = '{}', classes = '{class com.dongguo.shardingjdbc.ShardingJdbcDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3ce1e309, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@74e52303, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1aa7ecca, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@1d2adfbe, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@69ea3742], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@4f6fe058]; rollback [true]
2023-08-09 22:09:27.093  INFO 12836 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO t_user  ( uname )  VALUES  ( ? )
2023-08-09 22:09:27.093  INFO 12836 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: INSERT INTO t_user  ( uname )  VALUES  ( ? ) ::: [张三]
2023-08-09 22:09:27.267  INFO 12836 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-09 22:09:27.267  INFO 12836 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)
User(id=6, uname=张三)
2023-08-09 22:09:27.335  INFO 12836 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@33bc72d1 testClass = ReadwriteTest, testInstance = com.dongguo.shardingjdbc.ReadwriteTest@2917abdb, testMethod = testReadwrite@ReadwriteTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@1a75e76a testClass = ReadwriteTest, locations = '{}', classes = '{class com.dongguo.shardingjdbc.ShardingJdbcDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3ce1e309, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@74e52303, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1aa7ecca, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@1d2adfbe, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@69ea3742], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]

在配置中加入transactionalReadQueryStrategy: PRIMARY实现事务内读请求路由至主库

shardingsphere-readwrite.yaml

# 数据源配置
dataSources:master:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3306/db_userusername: rootpassword: 123456slave1:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3307/db_userusername: rootpassword: 123456slave2:dataSourceClassName: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.122.150:3308/db_userusername: rootpassword: 123456
#规则配置
rules:
- !READWRITE_SPLITTINGdataSources:myds:writeDataSourceName: masterreadDataSourceNames:- slave1- slave2transactionalReadQueryStrategy: PRIMARYloadBalancerName: alg_round#算法配置loadBalancers:alg_round:type: ROUND_ROBINalg_random:type: RANDOMalg_weight:type: WEIGHTprops:slave1: 1slave2: 2
#属性配置
props:sql-show: true

运行结果

2023-08-09 22:47:33.631  INFO 28972 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@33bc72d1 testClass = ReadwriteTest, testInstance = com.dongguo.shardingjdbc.ReadwriteTest@14eb2f67, testMethod = testTransactional@ReadwriteTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@1a75e76a testClass = ReadwriteTest, locations = '{}', classes = '{class com.dongguo.shardingjdbc.ShardingJdbcDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3ce1e309, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@74e52303, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1aa7ecca, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@1d2adfbe, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@69ea3742], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@7abbd5c1]; rollback [true]
2023-08-09 22:47:34.355  INFO 28972 --- [           main] ShardingSphere-SQL                       : Logic SQL: INSERT INTO t_user  ( uname )  VALUES  ( ? )
2023-08-09 22:47:34.355  INFO 28972 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: INSERT INTO t_user  ( uname )  VALUES  ( ? ) ::: [张三]
2023-08-09 22:47:34.530  INFO 28972 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-09 22:47:34.530  INFO 28972 --- [           main] ShardingSphere-SQL                       : Actual SQL: master ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=884300ef58d6)
User(id=3, uname=张三丰)
User(id=14, uname=张三)
2023-08-09 22:47:34.572  INFO 28972 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@33bc72d1 testClass = ReadwriteTest, testInstance = com.dongguo.shardingjdbc.ReadwriteTest@14eb2f67, testMethod = testTransactional@ReadwriteTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@1a75e76a testClass = ReadwriteTest, locations = '{}', classes = '{class com.dongguo.shardingjdbc.ShardingJdbcDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3ce1e309, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@74e52303, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1aa7ecca, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@1d2adfbe, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@69ea3742], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]

2.3、负载均衡测试

规则配置中负载均衡算法配置如果没有指定loadBalancerName,则使用默认的负载均衡算法 ROUND_ROBIN。

这里项目中shardingsphere.yaml中已经配置loadBalancerName: alg_round,alg_round对应的就是轮询ROUND_ROBIN

轮询算法

    @Testpublic void testLoadBalancer(){for (long i = 1L; i <= 3L; i++) {User user = userMapper.selectById(i);System.out.println(user);}}

运行

2023-08-09 23:00:05.803  INFO 17756 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT id,uname FROM t_user WHERE id=? 
2023-08-09 23:00:05.803  INFO 17756 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT id,uname FROM t_user WHERE id=?  ::: [1]
User(id=1, uname=zhang3)
2023-08-09 23:00:05.880  INFO 17756 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT id,uname FROM t_user WHERE id=? 
2023-08-09 23:00:05.880  INFO 17756 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT id,uname FROM t_user WHERE id=?  ::: [2]
User(id=2, uname=e981b9526f35)
2023-08-09 23:00:05.884  INFO 17756 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT id,uname FROM t_user WHERE id=? 
2023-08-09 23:00:05.884  INFO 17756 --- [           main] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT id,uname FROM t_user WHERE id=?  ::: [3]
User(id=3, uname=张三丰)

也可以在web请求中测试负载均衡

package com.dongguo.shardingjdbc.controller;import com.dongguo.shardingjdbc.entity.User;
import com.dongguo.shardingjdbc.mapper.UserMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @author dongguo* @date 2023/8/9* @description:*/
@RestController
@RequestMapping("/user")
@Api(tags = "用戶管理")
public class UserController {@Autowiredprivate UserMapper userMapper;/*** 测试负载均衡策略*/@ApiOperation("获取用户列表,测试负载均衡策略")@GetMapping("/selectAll")public void selectAll(){List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}
}

这里我们用swagger去访问

image-20230810193822776

第一次访问

2023-08-10 19:42:29.926  INFO 18296 --- [nio-8080-exec-7] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 19:42:29.927  INFO 18296 --- [nio-8080-exec-7] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)

第二次访问

2023-08-10 19:43:01.538  INFO 18296 --- [nio-8080-exec-8] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 19:43:01.538  INFO 18296 --- [nio-8080-exec-8] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)

第三次访问

2023-08-10 19:43:19.598  INFO 18296 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 19:43:19.598  INFO 18296 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)

第四次访问

2023-08-10 19:43:31.283  INFO 18296 --- [io-8080-exec-10] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 19:43:31.283  INFO 18296 --- [io-8080-exec-10] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)

随机算法

只需要在shardingsphere-readwrite.yaml中的规则配置修改为loadBalancerName: alg_random

第一次访问

2023-08-10 22:12:04.116  INFO 15908 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:12:04.116  INFO 15908 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)

第二次访问

2023-08-10 22:12:04.738  INFO 15908 --- [io-8080-exec-10] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:12:04.738  INFO 15908 --- [io-8080-exec-10] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)

第三次访问

2023-08-10 22:12:05.366  INFO 15908 --- [nio-8080-exec-1] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:12:05.366  INFO 15908 --- [nio-8080-exec-1] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)

第四次访问

2023-08-10 22:12:05.931  INFO 15908 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:12:05.932  INFO 15908 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)

权重算法

shardingsphere-readwrite.yaml中算法配置slave1权重为1,slave2权重为2

    alg_weight:type: WEIGHTprops:slave1: 1slave2: 2

规则配置修改为loadBalancerName: alg_weight,共访问九次,其中slave1处理请求3次,slave2处理请求6次,正好1:2.

2023-08-10 22:21:24.846  INFO 18216 --- [nio-8080-exec-1] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:24.846  INFO 18216 --- [nio-8080-exec-1] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:25.498  INFO 18216 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:25.498  INFO 18216 --- [nio-8080-exec-2] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:26.203  INFO 18216 --- [nio-8080-exec-3] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:26.203  INFO 18216 --- [nio-8080-exec-3] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)
2023-08-10 22:21:27.147  INFO 18216 --- [nio-8080-exec-4] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:27.147  INFO 18216 --- [nio-8080-exec-4] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)
2023-08-10 22:21:27.891  INFO 18216 --- [nio-8080-exec-5] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:27.892  INFO 18216 --- [nio-8080-exec-5] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:28.563  INFO 18216 --- [nio-8080-exec-6] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:28.563  INFO 18216 --- [nio-8080-exec-6] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:29.195  INFO 18216 --- [nio-8080-exec-7] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:29.196  INFO 18216 --- [nio-8080-exec-7] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:29.787  INFO 18216 --- [nio-8080-exec-8] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:29.787  INFO 18216 --- [nio-8080-exec-8] ShardingSphere-SQL                       : Actual SQL: slave2 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=e981b9526f35)
User(id=3, uname=张三丰)
2023-08-10 22:21:30.562  INFO 18216 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Logic SQL: SELECT  id,uname  FROM t_user
2023-08-10 22:21:30.563  INFO 18216 --- [nio-8080-exec-9] ShardingSphere-SQL                       : Actual SQL: slave1 ::: SELECT  id,uname  FROM t_user
User(id=1, uname=zhang3)
User(id=2, uname=75a5627e4b69)
User(id=3, uname=张三丰)

整合swagger的部分就不写出来了,可以查看完整代码传送门:

https://github.com/dongguo4812/shardingsphere-study/tree/master/sharding-jdbc-demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/51967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

resource doesn‘t have a corresponding Go package.

resource doesnt have a corresponding Go package. GO这个鬼东西不能直接放src下。 ************ Building Go project: ProjectGoTest ************with GOPATH: D:\Go;D:\eclipse-jee-oxygen-2-win32-x86_64\workspace\ProjectGoTest >> Running: D:\Go\bin\go.exe …

爱校对发布全新PDF校对工具,为用户带来更为便捷的校正体验

随着数字化文档使用的普及&#xff0c;PDF格式已经成为最为广泛使用的文件格式之一。为满足广大用户对于高效、准确PDF文档校对的需求&#xff0c;爱校对团队经过深入研发&#xff0c;正式推出全新的PDF校对工具&#xff01; 这一全新工具针对PDF文件格式进行了深度优化&#…

k8s 常用命令(四)

12、删除pod中的nginx服务及service [rootmaster ~]# kubectl delete deployment nginx -n kube-public [rootmaster ~]# kubectl delete svc -n kube-public nginx-service 13、查看endpoint的信息 [rootmaster ~]# kubectl get endpoints 14、修改/更新&#xff08;镜像、…

机器学习十大算法之七——随机森林

0 引言 集成学习&#xff08;ensemble learning&#xff09;是时下非常流行的机器学习算法&#xff0c;它本身不是一个单独的机器学习算法&#xff0c;而是通过在数据上构建多个横型&#xff0c;集成所有模型的建模结果&#xff0c;基本上所有的机器学习领域都可以看到集成学习…

11.redis持久化

1.redis持久化 Redis的所有数据都是保存在内存中&#xff0c;因此redis重启后数据就丢失了&#xff0c;所以需要不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”)&#xff1b;或者把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。 …

Python遥感图像处理应用篇037 GDAL+Scikit-image遥感图像主成分分析PCA

1.计算效果图 使用多波段遥感图像进行主成分分析,这里使用了6个波段的数据计算和显示效果图如下:左边是原图像IR+R+G显示图,右边是计算得到的3个主成分组合显示的RGB图像。 2.计算方法详解 使用GDAL库读取和保存遥感图像,使用numpy对图像数据进行相应的变换和计算,使用…

IDEA创建Mybatis格式XML文件

设置位置&#xff1a;File | Settings | Editor | File and Code Templates 选择Files&#xff0c;点击号 Name中输入xml模板名&#xff08;名称自行决定&#xff09;&#xff0c;后缀名extension输入xml&#xff08;固定&#xff09; 内容处输入Mybatis的xml文件模板内容&…

javaWeb差缺补漏(二)【针对于自身知识点掌握情况】

javaweb 建立数据库连接 1、编写数据库建立连接工具类 public class JDBCUtils{private static DruidDataSource dataSource;static{try{Properties propertis new Properties();InputStream inputStream JDBCUtils.class.getClassLoader().getResourceAsStream(jdbc.prope…

【光学镀膜】-- USPM反射率、LAB

系列文章目录 文章目录 系列文章目录前言一、OLYMPUS(奥林巴斯)1.实现高速测定2.最适用于测定细小部件、镜片的反射率3.测定反射率时&#xff0c;不需要背面防反射处理4.可选择的膜厚测定方法 二、USPM-RU III1.介绍2.特点3.参数4.光源5.特长6.测定原理7.规格 三、USPM-W1.特征…

csdn冷知识:如何在csdn里输入公式或矩阵

目录 1 输入公式 2 输入矩阵 3 如何输入复杂公式 4 如何修改&#xff0c;已经生成的公式 1 输入公式 进入编辑模式点击右边的菜单&#xff1a;公式然后进入公式编辑器&#xff0c;选择右边的 ... 可以选择大括号等&#xff0c;右边还有矩阵符号选择后你需要创建几行几列的…

PL端案例开发手册

目 录 前 言 1 工程编译、程序加载方法 1.1 工程编译 1.2 程序加载 2 led-flash 2.1 案例说明 2.2 操作说明 2.3 关键代码 更多帮助 前 言 本文主要介绍PL端案例的使用说明&#xff0c;适用开发环境&#xff1a;Windows 7/10 64bit、Xilinx Unified 20…

Tomcat的安装与介绍

首先我们先了解一下什么是服务器&#xff1f;什么是服务器软件&#xff1f; 什么是服务器&#xff1f;安装了服务器软件的计算机。 什么是服务器软件&#xff1f; 服务器软件是一种运行在服务器操作系统上&#xff0c;用于接收和处理客户端请求&#xff0c;并提供相应服务和资…

PySide6学习笔记--gui小模版使用

一、界面绘制 1.desiner画图 2.画图代码 # -*- coding: utf-8 -*-################################################################################ ## Form generated from reading UI file t1gui.ui ## ## Created by: Qt User Interface Compiler version 6.5.2 ## ##…

第9天----【位运算进阶之----按位取反(~)】(附补码,原码讲解)

今天我们来谈谈按位取反这件事。 简单来说&#xff0c;按位取反就是先将一个数写成其二进制表达形式&#xff0c;然后1变0&#xff0c;0变1。下面就让我们展开深入地讨论吧&#xff01; 文章目录 一、预备知识&#xff1a;1. 原码&#xff1a;定义&#xff1a;优缺点&#xff…

Mac操作系统上设置和配置PPPoE连接

嗨&#xff0c;在使用Mac的小伙伴么&#xff01;你是否在Mac操作系统上尝试设置和配置PPPoE连接&#xff0c;却不知道怎么设置&#xff1f;别担心&#xff0c;今天我将为你一步步教你如何在Mac上进行设置和配置。无论你是新手还是有经验的用户&#xff0c;本文都将帮助你轻松完…

node.js 简单使用 开始

1.概要 问&#xff1a;体验一下node.js 看一下如何运行。 答&#xff1a;使用命令 node 文件名.js 2.举例 2.1 代码准备(main.js) console.log(第一行node.js代码); 2.2 运行效果

Qt 获取文件图标、类型 QFileIconProvider

Qt中获取系统图标、类型是通过QFileIconProvider来实现的&#xff0c;具体如下&#xff1a; 一、Qt获取系统文件图标1、获取文件夹图标QFileIconProvider icon_provider;QIcon icon icon_provider.icon(QFileIconProvider::Folder);2、获取指定文件图标QFileInfo file_info(n…

【JVM基础】JVM入门基础

目录 JVM的位置三种 JVMJVM体系结构类加载器双亲委派机制概念例子作用 沙箱安全机制组成沙箱的基本组件 NativeJNI&#xff1a;Java Native Interface&#xff08;本地方法接口&#xff09;Native Method Stack&#xff08;本地方法栈&#xff09; PC寄存器&#xff08;Program…

牛客python练习2

1 解析&#xff1a;赋值操作&#xff08;aXX,ba&#xff09;&#xff0c;a&#xff0c;b指向同一内存空间。当a,b是不可变类型时&#xff0c;a变&#xff0c;a 值变&#xff0c;id变&#xff0c;但是b不变&#xff0c;b的id也不变&#xff1b;当a,b是可变类型时&#xff0c;a变…

c语言函数指针和指针函数的区别,以及回调函数的使用。

函数指针是什么&#xff0c;函数指针本质也是指针&#xff0c;不过是指向函数的指针&#xff0c;存储的是函数的地址。 指针函数是什么,指针函数其实就是返回值是指针的函数&#xff0c;本质是函数。 函数指针是如何定义的呢&#xff0c;如下 void (*pfun)(int a,int b) 这…