一、依赖以及配置
1.1依赖
ruoyi-common 下面引入依赖
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
父pom.xml 下面,控制版本
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
对应版本:
<dynamic-ds.version>3.5.2</dynamic-ds.version>
1.2 yml中配置
- datasource: 配置项下面配置了master、slave2个数据源
- master、slave 这2个数据源 共用hikari连接池配置
- 此处演示了oracle 等其他数据源配置
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/ry-vue-plus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源 lazy: true 用不到不会加载从库
slave:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ry-vue-plus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间,默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
解释:
type: ${spring.datasource.type} ,引用的是配置: spring: datasource: type: com.zaxxer.hikari.HikariDataSource
二、连接测试
2.1未加上多数据源注解
默认连接主库:
@RestController
@Slf4j
@SaIgnore
@RequiredArgsConstructor
public class DynamicController {
private final ITestDemoService iTestDemoService;
@GetMapping("testDynamic1")
public void test() {
TestDemoVo testDemoVo = iTestDemoService.queryById(2L);
Console.log("打印数据:{}", testDemoVo);
}
}
打印结果:
打印数据:TestDemoVo(id=2, deptId=102, userId=3, orderNum=2, testKey=主库节点, value=22222, createTime=Tue Jul 23 10:18:35 GMT+08:00 2024, createBy=null, updateTime=null, updateBy=null) 2024-07-23 10:39:55 [XNIO-1 task-1] INFO c.r.f.i.PlusWebInvokeTimeInterceptor - [PLUS]结束请求 => URL[GET /testDynamic1],耗时:[49]毫秒
2.2 加上多数据源注解
@DS("slave")后,打印从库节点数据,如下:
@GetMapping("testDynamic1")
@DS("slave")
public void test() {
TestDemoVo testDemoVo = iTestDemoService.queryById(2L);
Console.log("打印数据:{}", testDemoVo);
}
打印结果:
打印数据:TestDemoVo(id=2, deptId=102, userId=3, orderNum=2, testKey=从库节点, value=22222, createTime=Tue Jul 23 10:18:35 GMT+08:00 2024, createBy=null, updateTime=null, updateBy=null) 2024-07-23 11:14:09 [XNIO-1 task-1] INFO c.r.f.i.PlusWebInvokeTimeInterceptor - [PLUS]结束请求 => URL[GET /testDynamic1],耗时:[235]毫秒
注意,失效场景:
- 持久层使用 @DS注解,只会在自定义的方法上生效
- 如果标注在 BaseMapper 接口是不会生效,还是查询主库,原因是selectById 是内部调用this.,如下代码。而@DS注解的AOP是对内部调用无法产生作用。所以注解要写在AOP可以作用的地方
/** * 根据 ID 查询 */ default <C> C selectVoById(Serializable id, Class<C> voClass) { T obj = this.selectById(id); if (ObjectUtil.isNull(obj)) { return null; } return BeanCopyUtils.copy(obj, voClass); }
重点:@DS注解注解,推荐写在实现类的方法上
错误演示:selectById是MyBatis是自带事项方法,不生效如下;
/**
*不会生效:selectById 是 BaseMapper 定义接口
*/
@Override
@DS("slave")
TestDemo selectById(Serializable id);
/**
*会生效:selectByIdOfMy 是自定义接口
*/
@DS("slave")
TestDemo selectByIdOfMy(Serializable id);
三、轮询访问
3.1演示
- 如图下面配置3个数据源 :slave_1、slave_2、slave_3
- 如果注解还是这样写: @DS("slave") ,则会循环调用3个数据源(默认机制)
@GetMapping("testDynamic1") @DS("slave") public void test() { TestDemoVo testDemoVo = iTestDemoService.queryById(2L); Console.log("打印数据:{}", testDemoVo); }
打印结果:
打印数据:TestDemoVo(id=2, deptId=102, userId=3, orderNum=2, testKey=从库节点1, value=111, createTime=Tue Jul 23 10:18:35 GMT+08:00 2024, createBy=null, updateTime=null, updateBy=null) 2024-07-23 11:20:09 [XNIO-1 task-1] INFO c.r.f.i.PlusWebInvokeTimeInterceptor - [PLUS]结束请求 => URL[GET /testDynamic1],耗时:[235]毫秒 打印数据:TestDemoVo(id=2, deptId=102, userId=3, orderNum=2, testKey=从库节点2, value=222, createTime=Tue Jul 23 10:18:35 GMT+08:00 2024, createBy=null, updateTime=null, updateBy=null) 2024-07-23 11:21:11 [XNIO-1 task-1] INFO c.r.f.i.PlusWebInvokeTimeInterceptor - [PLUS]结束请求 => URL[GET /testDynamic1],耗时:[212]毫秒 打印数据:TestDemoVo(id=2, deptId=102, userId=3, orderNum=2, testKey=从库节点3, value=333, createTime=Tue Jul 23 10:18:35 GMT+08:00 2024, createBy=null, updateTime=null, updateBy=null) 2024-07-23 11:22:13 [XNIO-1 task-1] INFO c.r.f.i.PlusWebInvokeTimeInterceptor - [PLUS]结束请求 => URL[GET /testDynamic1],耗时:[187]毫秒
slave_1、slave_2、slave_3 数据源配置:
--- # 多数据源配置 HikariDataSource
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源1
slave_1:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localshost:3306/ry-vue-plus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源2
slave_2:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localshost:3306/ry-vue-plus2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源3
slave_3:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localshost:3306/ry-vue-plus2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
3.2数据源策略
- DynamicDataSourceProperties.class 定义了每一个数据源,以及对应动态数据源策略。
- LoadBalanceDynamicDataSourceStrategy就是默认负载均衡策略
/**
* 每一个数据源
*/
private Map<String, DataSourceProperty> datasource = new LinkedHashMap<>();
/**
* 多数据源选择算法clazz,默认负载均衡算法
*/
private Class<? extends DynamicDataSourceStrategy> strategy = LoadBalanceDynamicDataSourceStrategy.class;
查看器策略接口:com.baomidou.dynamic.datasource.strategy.DynamicDataSourceStrategy 的实现类有2个:
- RandomDynamicDataSourceStrategy.class 随机策略
LoadBalanceDynamicDataSourceStrategy 负载均衡策略(默认)
3.3 配置策略
指定 strategy 属性就行如下,指定RandomDynamicDataSourceStrategy随机策略:
。。。。。。。省里配置
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间,默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
strategy: com.baomidou.dynamic.datasource.strategy.RandomDynamicDataSourceStrategy