>[项目220510-dynamicDataSource仓库地址](https://gitee.com/anyway2025/guide)
## 原理
**java提供了一个接口 java.sql.DataSource 用来获取数据库连接 getConnnection()**,动态多数据源就是在该接口基础上实现的。
Spring中 AbstractRoutingDataSource 实现了该 DataSource 接口
```java
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
...
/**
* 根据determineCurrentLookupKey()决定使用哪个数据源,如果为空,则使用默认数据源
*/
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}
/**
* 抽象方法,返回数据源map的key,用来决定具体使用哪个数据源
*/
@Nullable
protected abstract Object determineCurrentLookupKey();
```
抽象方法 `determineCurrentLookupKey()` 是暴露给开发者的,我们可以通过实现该方法在不同数据源之间切换。
## SpringBoot实践
### 1. 配置多数据源
在 application.yml 如下配置
```yaml
spring:
datasource:
# 数据源类型
type: com.alibaba.druid.pool.DruidDataSource
# 默认数据源
default-datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db0?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: 123456
# 多数据源
target-datasources:
datasource1:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: 123456
datasource2:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: 123456
# druid 默认配置
druid:
# 初始连接数
initial-size: 10
# 最大连接池数量
max-active: 100
# 最小连接池数量
min-idle: 10
# 配置获取连接等待超时的时间
max-wait: 60000
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /monitor/druid/*
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
# MyBatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.guide
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
```
> 此处配置的名称(如 defaultDataSource、targetDataSources)的命名并无特殊要求,只要和下面第3步的 DataSourceConfig 中对应起来就可以
使用 Druid 数据源的话,要在 pom.xml 中引入依赖
```xml
com.alibaba
druid-spring-boot-starter
1.1.10
```
### 2. 实现数据源
DynamicDataSource 动态数据源,在多个数据源之间切换
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource(DataSource defaultTargetDataSource, Map