package com.springboot.multiplyds.datasource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.jdbc.DataSourceBuilder;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 自定义多数据源类
*/
public class MultiplyDataSource extends HikariDataSource implements InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(MultiplyDataSource.class);
/**
* 所有数据源
*/
private final Map<String, HikariDataSource> allDataSource = new ConcurrentHashMap<>();
/**
* 其他需要切换控制的数据源
*/
private final Map<String, String> dsInfoIdKeyMap = new ConcurrentHashMap<>();
public MultiplyDataSource() {
super();
}
public MultiplyDataSource(HikariConfig configuration) {
super(configuration);
}
public Map<String, HikariDataSource> getAllDataSource() {
return allDataSource;
}
/**
* 获取数据源,如果多线程下设置了数据源就取设置的,如果没有取到就用默认的
*
* @return 数据源
*/
public DataSource getMultiplyDataSource() throws SQLException {
String key = MultiplyDataSourceKeyHolder.getKey();
DataSource dataSource;
if (key == null) {
dataSource = this;
} else {
dataSource = this.allDataSource.get(dsInfoIdKeyMap.get(key));
}
if (dataSource == null) {
throw new SQLException("未找到和key[" + key + "]匹配的数据源。");
}
return dataSource;
}
/**
* 如果不存在,添加一个新数据源
*
* @param key 数据连接信息
* @return 数据源
* @throws SQLException
*/
private HikariDataSource createIfNotExistsDataSource(DataSourceInfo key) throws SQLException {
HikariDataSource dataSource = allDataSource.get(key.toString());
String keyToString = key.toString();
if (dataSource == null) {
synchronized (allDataSource) {
if (allDataSource.get(keyToString) == null) {
HikariDataSource newDataSource = DataSourceBuilder.derivedFrom(this).type(HikariDataSource.class).driverClassName(key.getDriverClassName()).url(key.getUrl()).username(key.getUsername()).password(key.getPassword()).build();
newDataSource.setLoginTimeout(this.getLoginTimeout());
newDataSource.setValidationTimeout(this.getValidationTimeout());
newDataSource.setConnectionTimeout(this.getConnectionTimeout());
newDataSource.setIdleTimeout(this.getIdleTimeout());
newDataSource.setMaxLifetime(this.getMaxLifetime());
newDataSource.setMaximumPoolSize(this.getMaximumPoolSize());
newDataSource.setMinimumIdle(this.getMinimumIdle());
allDataSource.put(keyToString, newDataSource);
dataSource = newDataSource;
} else {
dataSource = allDataSource.get(keyToString);
}
}
}
return dataSource;
}
@Override
public Connection getConnection() throws SQLException {
DataSource multiplyDataSource = this.getMultiplyDataSource();
if (this.equals(multiplyDataSource)) {
return super.getConnection();
}
return multiplyDataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
DataSource multiplyDataSource = this.getMultiplyDataSource();
if (this.equals(multiplyDataSource)) {
return super.getConnection(username, password);
}
return this.getMultiplyDataSource().getConnection(username, password);
}
/**
* 更新数据源信息
*
* @param newDatasourceList 数据源列表
*/
public void updateMultiplyDataSources(List<DataSourceInfo> newDatasourceList) {
if (newDatasourceList == null) {
//清理之前的数据源
if (dsInfoIdKeyMap.size() > 0) {
dsInfoIdKeyMap.values().forEach(row -> allDataSource.remove(row).close());
dsInfoIdKeyMap.clear();
}
} else {
newDatasourceList.forEach(row -> {
try {
allDataSource.putIfAbsent(row.toString(), createIfNotExistsDataSource(row));
} catch (SQLException e) {
e.printStackTrace();
LOGGER.error("MultiplyDataSource init datasource exception:{}", e.getMessage());
}
});
//通过toString()为key,删除为用到的,数据源信息可能会被修改,id未该,所以不通过id删除。
if (dsInfoIdKeyMap.size() > 0) {
Set<String> keySet = newDatasourceList.stream().map(DataSourceInfo::toString).collect(Collectors.toSet());
dsInfoIdKeyMap.values().forEach(key -> {
if (!keySet.contains(key)) {
allDataSource.remove(key).close();
}
});
}
dsInfoIdKeyMap.clear();
newDatasourceList.forEach(row -> dsInfoIdKeyMap.put(row.getId(), row.toString()));
}
}
@Override
public void afterPropertiesSet() {
allDataSource.put(DataSourceInfo.of(this.getDriverClassName(), this.getJdbcUrl(), this.getUsername(), this.getPassword()).toString(), this);
LOGGER.info("MultiplyDataSource init,datasource.size:{}", getAllDataSource().size());
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
spring boot动态多数据源demo
共21个文件
java:8个
sql:4个
gradle:2个
5星 · 超过95%的资源 需积分: 34 8 下载量 147 浏览量
2022-07-17
17:52:05
上传
评论 1
收藏 70KB ZIP 举报
温馨提示
在查阅大量多数据源配置资料和文章并结合工作实践的基础上开发了一个简单实用的spring boot动态多数据源demo,该demo主要功能如下: 自定义多数据源类MultiplyDataSource(继承HikariDataSource),通过多线程类ThreadLocal控制当前需要使用的数据源id,实现多数据源动态切换查询功能(默认数据源和其他数据源都统一使用这一个,简化了配置)。 多数据源获取功能封装,通过类MultiplyDataSourceUpdateSchedule实现多数据源从yml配置文件获取,或者定时动态从默认数据库获取。 该demo使用内嵌数据库h2和derby运行,无需额外配置数据库就可运行。 demo中添加了多数据源查询api接口MultiplyDatasourceController,和单元测试ApplicationTests可直接运行测试效果。 该demo 使用gradle和maven都可以运行。
资源详情
资源评论
资源推荐
收起资源包目录
spring-boot-multiply-ds.zip (21个子文件)
pom.xml 3KB
gradle
wrapper
gradle-wrapper.jar 58KB
gradle-wrapper.properties 202B
src
test
resources
META-INF
spring.factories 148B
application.yml 1KB
sql
schema-h2.sql 377B
data-h2.sql 672B
java
com
springboot
multiplyds
springboot
ApplicationTests.java 1KB
main
resources
META-INF
spring.factories 148B
application.yml 1KB
templates
static
sql
schema-h2.sql 375B
data-h2.sql 293B
java
com
springboot
multiplyds
config
DataSourceConfig.java 1KB
api
base
MultiplyDatasourceController.java 2KB
Application.java 390B
datasource
DataSourceInfo.java 2KB
MultiplyDataSource.java 6KB
MultiplyDataSourceKeyHolder.java 936B
schedule
MultiplyDataSourceUpdateSchedule.java 2KB
settings.gradle 46B
build.gradle 710B
共 21 条
- 1
zoyation
- 粉丝: 122
- 资源: 9
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论10