first commit

This commit is contained in:
2023-06-13 21:41:02 +08:00
parent 27dd2c917a
commit c407eace59
19 changed files with 179 additions and 344 deletions

View File

@ -1,6 +1,5 @@
package com.qiaoba.common.database.config;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.qiaoba.common.base.constants.TenantConstant;
@ -8,12 +7,8 @@ import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.database.constants.DynamicDatasourceConstant;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.properties.DefaultDataSourceProperties;
import com.qiaoba.common.database.properties.MasterInfo;
import com.qiaoba.common.database.properties.PoolInfo;
import com.qiaoba.common.database.properties.SlaveInfo;
import com.qiaoba.common.database.properties.DataSourceProperties;
import com.qiaoba.common.database.service.DynamicDatasourceService;
import com.qiaoba.common.database.utils.JdbcUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
@ -21,7 +16,10 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@ -41,19 +39,19 @@ public class DynamicDataSourceConfig {
@Resource
private DynamicDataSourceContext dataSource;
@Resource
private DefaultDataSourceProperties defaultDataSourceProperties;
private DataSourceProperties dataSourceProperties;
@Resource
private DynamicDatasourceService dynamicDatasourceService;
/**
* 使用中的数据源
* 主要数据源
*/
public static Map<Object, Object> MASTER_SOURCE_MAP = new ConcurrentHashMap<>();
public static Map<Object, Object> PRIMARY_DATASOURCE_MAP = new ConcurrentHashMap<>();
/**
* 备用数据源
* 备用数据源-每次取0索引
*/
public static Map<String, List<SlaveInfo>> SLAVE_SOURCE_MAP = new ConcurrentHashMap<>();
public static Map<String, List<DynamicDataSource>> BACKUP_DATASOURCE_MAP = new ConcurrentHashMap<>();
/**
* 把DynamicDataSourceContext 纳入容器管理其他地方使用DynamicDataSourceConfig 类可以直接从容器取对象并调用freshDataSource方法
@ -67,72 +65,51 @@ public class DynamicDataSourceConfig {
}
private void initDefault() {
MasterInfo master = defaultDataSourceProperties.getMaster();
List<SlaveInfo> slaves = defaultDataSourceProperties.getSlaves();
// 将主数据源使用
addMasterMap(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID, buildDataSource(master.getDriver(), master.getUrl(), master.getUsername(), master.getPassword(), master.getPool()));
dataSource.freshDataSource(MASTER_SOURCE_MAP);
// 将从数据源备用
if (CollUtil.isNotEmpty(slaves)) {
for (int i = 0; i < slaves.size(); i++) {
if (!slaves.get(i).getIsUse()) {
slaves.remove(i);
}
}
if (CollUtil.isNotEmpty(slaves)) {
SLAVE_SOURCE_MAP.put(DynamicDatasourceConstant.SLAVE_PREFIX + TenantConstant.DEFAULT_TENANT_ID, slaves);
}
}
List<DynamicDataSource> dataSources = dataSourceProperties.getDataSources();
// 0索引作为主数据源
addPrimaryMap(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID, buildDataSource(dataSources.get(0)));
dataSources.remove(0);
// 非0索引的备用
addBackupMap(TenantConstant.DEFAULT_TENANT_ID, dataSources);
// 刷新数据源
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
private void initTenant() {
setDefaultSetting();
List<DynamicDataSource> dynamicDataSourceList = dynamicDatasourceService.loadAllTenantDatasource();
for (DynamicDataSource dynamicDataSource : dynamicDataSourceList) {
// 将主数据源加载
if (BaseEnum.YES.getCode().equals(dynamicDataSource.getIsMaster())) {
addMasterMap(DynamicDatasourceConstant.MASTER_PREFIX + dynamicDataSource.getTenantId(), buildDataSource(dynamicDataSource.getDriver(), dynamicDataSource.getUrl(), dynamicDataSource.getUsername(), dynamicDataSource.getPassword(), new PoolInfo(dynamicDataSource.getInitCount(), dynamicDataSource.getMinCount(), dynamicDataSource.getMaxCount())));
dataSource.freshDataSource(MASTER_SOURCE_MAP);
}
// 将从数据源备用
else {
if (Objects.isNull(SLAVE_SOURCE_MAP.get(DynamicDatasourceConstant.MASTER_PREFIX + dynamicDataSource.getTenantId()))) {
List<SlaveInfo> slaves = new ArrayList<>();
slaves.add(datasourceToSlave(dynamicDataSource));
SLAVE_SOURCE_MAP.put(DynamicDatasourceConstant.MASTER_PREFIX + dynamicDataSource.getTenantId(), slaves);
} else {
List<SlaveInfo> slaves = SLAVE_SOURCE_MAP.get(DynamicDatasourceConstant.MASTER_PREFIX + dynamicDataSource.getTenantId());
slaves.add(datasourceToSlave(dynamicDataSource));
Map<String, List<DynamicDataSource>> tenantDatasource = dynamicDatasourceService.loadAllTenantDatasource();
for (String tenantId : tenantDatasource.keySet()) {
List<DynamicDataSource> dataSources = tenantDatasource.get(tenantId);
for (int i = 0; i < dataSources.size(); i++) {
DynamicDataSource dynamicDataSource = dataSources.get(i);
if (BaseEnum.YES.getCode().equals(dynamicDataSource.getIsPrimary())) {
addPrimaryMap(DynamicDatasourceConstant.MASTER_PREFIX + tenantId, buildDataSource(dataSources.get(i)));
// 去除主要数据源,剩下皆为备用数据源
dataSources.remove(i);
}
}
// 备用数据源
addBackupMap(tenantId, dataSources);
}
BaseContext.clearAllHolder();
}
public void addTenantDataSource(String tenantId, String driver, String url, String username, String password, PoolInfo poolInfo) {
addMasterMap(DynamicDatasourceConstant.MASTER_PREFIX + tenantId, buildDataSource(driver, url, username, password, poolInfo));
dataSource.freshDataSource(MASTER_SOURCE_MAP);
// 刷新数据源
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
public void deleteTenantDataSource(String tenantId) {
MASTER_SOURCE_MAP.remove(DynamicDatasourceConstant.MASTER_PREFIX + tenantId);
dataSource.freshDataSource(MASTER_SOURCE_MAP);
PRIMARY_DATASOURCE_MAP.remove(DynamicDatasourceConstant.MASTER_PREFIX + tenantId);
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
private static Object buildDataSource(String driver, String url, String username, String password, PoolInfo poolInfo) {
boolean flag = JdbcUtil.checkConnect(driver, url, username, password);
if (!flag) {
log.error("数据源: " + url + " , 连接失败,请检查!");
return null;
}
private static Object buildDataSource(DynamicDataSource dynamicDataSource) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driver);
dataSource.setInitialSize(poolInfo.getInit());
dataSource.setMinIdle(poolInfo.getMin());
dataSource.setMaxActive(poolInfo.getMax());
dataSource.setUrl(dynamicDataSource.getUrl());
dataSource.setUsername(dynamicDataSource.getUsername());
dataSource.setPassword(dynamicDataSource.getPassword());
dataSource.setDriverClassName(dynamicDataSource.getDriver());
dataSource.setInitialSize(dynamicDataSource.getInitialSize());
dataSource.setMinIdle(dynamicDataSource.getMinIdle());
dataSource.setMaxActive(dynamicDataSource.getMaxActive());
try {
dataSource.init();
return dataSource;
@ -147,23 +124,28 @@ public class DynamicDataSourceConfig {
*/
@PreDestroy
public void close() {
Set<Map.Entry<Object, Object>> entries = MASTER_SOURCE_MAP.entrySet();
Set<Map.Entry<Object, Object>> entries = PRIMARY_DATASOURCE_MAP.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
DruidDataSource dataSource = (DruidDataSource) entry.getValue();
dataSource.close();
}
}
private void addMasterMap(String name, Object dataSource) {
private void addPrimaryMap(String name, Object dataSource) {
if (Objects.nonNull(dataSource)) {
MASTER_SOURCE_MAP.put(name, dataSource);
PRIMARY_DATASOURCE_MAP.put(name, dataSource);
}
}
private SlaveInfo datasourceToSlave(DynamicDataSource dynamicDataSource) {
SlaveInfo slaveInfo = BeanUtil.copyProperties(dynamicDataSource, SlaveInfo.class);
slaveInfo.setPool(new PoolInfo(dynamicDataSource.getInitCount(), dynamicDataSource.getMinCount(), dynamicDataSource.getMaxCount()));
return slaveInfo;
private void addBackupMap(String tenantId, List<DynamicDataSource> dataSources) {
if (CollUtil.isNotEmpty(dataSources)) {
BACKUP_DATASOURCE_MAP.put(tenantId, dataSources);
}
}
private void handleDataSources(String tenantId, List<DynamicDataSource> dataSources) {
}
public void setDefaultSetting() {

View File

@ -10,7 +10,7 @@ import lombok.NoArgsConstructor;
*
* @author ailanyin
* @version 1.0
* @date 2023-04-24 21:47:48
* @since 2023-06-13 20:24:31
*/
@Data
@Builder
@ -24,9 +24,9 @@ public class DynamicDataSource {
private String tenantId;
/**
* 主
* 主要数据源
*/
private String isMaster;
private String isPrimary;
/**
* 数据库-url
@ -51,16 +51,16 @@ public class DynamicDataSource {
/**
* 连接池-初始化大小
*/
private Integer initCount;
private Integer initialSize;
/**
* 连接池-最小空闲数
* 连接池-最小空闲线程
*/
private Integer minCount;
private Integer minIdle;
/**
* 连接池-最大连接
* 连接池-最大连接池数量
*/
private Integer maxCount;
private Integer maxActive;
}

View File

@ -2,7 +2,7 @@ package com.qiaoba.common.database.factories;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.config.DynamicDataSourceContext;
import com.qiaoba.common.database.properties.DefaultDataSourceProperties;
import com.qiaoba.common.database.properties.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -27,8 +27,8 @@ public class DynamicDataSourceFactory {
}
@Bean
public DefaultDataSourceProperties defaultDataSourceProperties() {
return new DefaultDataSourceProperties();
public DataSourceProperties defaultDataSourceProperties() {
return new DataSourceProperties();
}
}

View File

@ -1,5 +1,6 @@
package com.qiaoba.common.database.properties;
import com.qiaoba.common.database.entity.DynamicDataSource;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -9,12 +10,11 @@ import java.util.List;
@Component
@ConfigurationProperties(prefix = "qiaoba.datasource")
@ConfigurationProperties(prefix = "qiaoba")
@Data
@EnableConfigurationProperties
public class DefaultDataSourceProperties {
public class DataSourceProperties {
private MasterInfo master;
private List<DynamicDataSource> dataSources;
private List<SlaveInfo> slaves;
}

View File

@ -1,19 +0,0 @@
package com.qiaoba.common.database.properties;
import lombok.Data;
/**
* 数据源-主库-信息
*
* @author ailanyin
* @version 1.0
* @since 2023-04-23 15:37:43
*/
@Data
public class MasterInfo {
private String driver;
private String url;
private String username;
private String password;
private PoolInfo pool;
}

View File

@ -1,33 +0,0 @@
package com.qiaoba.common.database.properties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 数据源连接池信息
*
* @author ailanyin
* @version 1.0
* @since 2023-04-23 15:37:43
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PoolInfo {
/**
* 初始连接数
*/
private Integer init;
/**
* 最小空闲数
*/
private Integer min;
/**
* 最大连接数
*/
private Integer max;
}

View File

@ -1,25 +0,0 @@
package com.qiaoba.common.database.properties;
import lombok.Data;
/**
* 数据源-从库-信息
*
* @author ailanyin
* @version 1.0
* @since 2023-04-23 15:37:43
*/
@Data
public class SlaveInfo {
private Boolean isUse = true;
private String driver;
private String url;
private String username;
private String password;
/**
* 权重
*/
private Integer weight = 1;
private PoolInfo pool;
}

View File

@ -3,6 +3,7 @@ package com.qiaoba.common.database.service;
import com.qiaoba.common.database.entity.DynamicDataSource;
import java.util.List;
import java.util.Map;
/**
* 动态数据源接口
@ -16,7 +17,7 @@ public interface DynamicDatasourceService {
/**
* 加载所有租户的数据源
*
* @return 数据源集合
* @return 数据源集合 key: tenantId | value: list
*/
List<DynamicDataSource> loadAllTenantDatasource();
Map<String, List<DynamicDataSource>> loadAllTenantDatasource();
}

View File

@ -1,107 +1,45 @@
{
"groups": [
{
"name": "qiaoba.datasource",
"type": "com.qiaoba.common.database.properties.DefaultDataSourceProperties",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
}
],
"groups": [],
"properties": [
{
"name": "qiaoba.datasource.master",
"type": "com.qiaoba.common.database.properties.MasterInfo",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"name": "qiaoba.dataSources",
"type": "java.util.List<com.qiaoba.common.database.entity.DynamicDataSource>",
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.driver",
"name": "qiaoba.datasources.driver",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.url",
"name": "qiaoba.datasources.url",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.username",
"name": "qiaoba.datasources.username",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.password",
"name": "qiaoba.datasources.password",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.pool",
"type": "com.qiaoba.common.database.properties.PoolInfo",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.master.pool.init",
"name": "qiaoba.datasources.initial-size",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.pool.min",
"name": "qiaoba.datasources.min-idle",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
},
{
"name": "qiaoba.datasource.master.pool.max",
"name": "qiaoba.datasources.max-active",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves",
"type": "java.util.List<com.qiaoba.common.database.properties.SlaveInfo>",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.url",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.username",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.password",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.weight",
"type": "java.lang.String",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.is-use",
"type": "java.lang.Boolean",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties",
"defaultValue": true
},
{
"name": "qiaoba.datasource.slaves.pool",
"type": "com.qiaoba.common.database.properties.PoolInfo",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.pool.init",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.pool.min",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
},
{
"name": "qiaoba.datasource.slaves.pool.max",
"type": "java.lang.Integer",
"sourceType": "com.qiaoba.common.database.properties.DefaultDataSourceProperties"
"sourceType": "com.qiaoba.common.database.properties.DataSourceProperties"
}
],
"hints": []