环境:MySQL主从数据库。如需要搭建可参考上一篇文章:MySQL主从数据库简单搭建
数据库使用主从可确保数据一致性,示例是基于一个完整的项目之上做了一些修改,为测试效果直接连接了两个非主从配置的数据库,其中只有测试的数据表内容不同其余内容全部相同。
方案参考:MySQL读写分离的三种实现方案
一、应用层(动态数据源切换)实现
优点: 1、不需要引入中间件; 2、 理论上支持任何数据库;
缺点: 1、侵入性强; 2、 根据具体的 Service 方法是否会操作数据,注入不同的数据源;
1、引入动态数据源依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.5</version>
</dependency>
2、配置文件修改
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.100.205:3306/mydb?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: '123456'
driver-class-name: com.mysql.cj.jdbc.Driver
initial-size: 5 # 初始连接数
max-active: 50 # 最大连接数
min-idle: 5 # 最小空闲连接数
validation-query: SELECT 1 # 验证连接是否有效的 SQL 查询语句
test-while-idle: true # 空闲时验证连接是否有效
test-on-borrow: false # 获取连接时验证连接是否有效
test-on-return: false # 归还连接时验证连接是否有效
time-between-eviction-runs-millis: 60000 # 连接回收的时间间隔
min-evictable-idle-time-millis: 300000 # 连接在池中最小生存的时间
slave_1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.100.5:3306/mydb?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: '123456'
driver-class-name: com.mysql.cj.jdbc.Driver
initial-size: 5
max-active: 50
min-idle: 5
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
3、ServiceImpl相关实现中添加注解,指定切换从数据库
@Override
public void getById() {
userMapper.getCount();
}
@DS("slave")
@Override
public void getById2() {
userMapper.getCount2();
}
由于在数据源中配置了primary: master,默认操作都会从主库执行,使用注解@DS切换数据源,此注解也可直接用于类文件上,同时存在方法注解优先于类上注解。
4、测试验证
两个方法的查询语句一样,但设置两个测试数据库查询的表的内容有所不同,如果能查出对应的值说明读写分离成功。
项目启动成功会打印日志:
5、遇到问题
1、如果启动失败,可能是由于修改数据库配置,部分配置文件不匹配,需要注释掉。
比如示例项目中有未修改之前的配置类。
2、SpringBoot 启动时自动配置数据库信息导致启动失败,项目启动类添加注解。
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
因为 DruidDataSourceAutoConfigure 在 DynamicDataSourceAutoConfiguration 之前会注入一个 DataSourceWrapper,会在原生的 spring.datasource 下找 url,username,password 信息,在启动类上排除掉自动配置类即可。
二、ShardingSphere-jdbc 实现
优点: 1、做SQL解析,自动实现读写分离; 2、 将事务都管理起来;
缺点: 1、存在侵入性(需要配置在代码中);
ShardingSphere参考文档:ShardingSphere 文档
ShardingSphere源码:ShardingSphere源码
1、引入ShardingSphere的Jar包依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
2、配置文件修改
spring:
shardingsphere:
# 数据源相关配置
datasource:
# 数据源名称
names: master,s1
# MySQL master数据源
master:
# 数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.100.205:3306/shardingsphere_demo?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: 123456
# slave数据源
s1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.100.5:3306/shardingsphere_demo?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: root
password: 123456
masterslave:
load-balance-algorithm-type: round_robin
name: ms
master-data-source-name: master
slave-data-source-names: s1
# 其他属性
props:
# 开启SQL显示
sql.show: true
3、测试验证
写好测试代码,简单的数据库操作查询、新增即可,主要是为了测试查询走从库,对数据库操作走主库。
启动成功,控制台会打印初始化了两个数据库:
执行查询时,控制台输出:
执行新增时,控制台输出:
4、遇到问题
1、如果是在原有项目上改数据库配置,记得将nacos中原有数据库相关配置注释掉,原有项目中数据库配置类相关内容也要注释掉。
2、最初使用的是 4.1.1 版本,启动服务总是报错启动失败。
Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.mybatis.spring.support.SqlSessionDaoSupport.checkDaoConfig(SqlSessionDaoSupport.java:122)
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:73)
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 49 common frames omitted
上网找解决方案,最终处理是将版本降低了。
版本降低之后启动还有报错,根据报错信息又加了一个配置,最终启动成功。
spring:
main:
allow-bean-definition-overriding: true
参考推荐:【MySQL系列】真香!基于ShardingSphere-JDBC的MySQL读写分离