diff --git a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/BackupDatasourceContext.java b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/BackupDatasourceContext.java index aa5aee8..0d983e4 100644 --- a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/BackupDatasourceContext.java +++ b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/BackupDatasourceContext.java @@ -45,7 +45,9 @@ public class BackupDatasourceContext { * @param list 数据源集合 */ private void set(String tenantId, List list) { - redisTemplate.opsForValue().set(BACKUP_DATASOURCE_KET + tenantId, list); + if (CollUtil.isNotEmpty(list)) { + redisTemplate.opsForValue().set(BACKUP_DATASOURCE_KET + tenantId, list); + } } /** @@ -59,6 +61,14 @@ public class BackupDatasourceContext { if (CollUtil.isEmpty(dataSourceList)) { set(dataSource.getTenantId(), ListUtil.toList(dataSource)); } else { + for (DynamicDataSource dynamicDataSource : dataSourceList) { + // 删除原来的 + if (dataSource.getUrl().equals(dynamicDataSource.getUrl()) + && dataSource.getTenantId().equals(dynamicDataSource.getTenantId())) { + dataSourceList.remove(dataSource); + break; + } + } dataSourceList.add(dataSource); set(dataSource.getTenantId(), dataSourceList); } @@ -69,13 +79,14 @@ public class BackupDatasourceContext { List dataSourceList = get(dynamicDataSource.getTenantId()); if (CollUtil.isNotEmpty(dataSourceList)) { for (DynamicDataSource dataSource : dataSourceList) { - if (dataSource.getUrl().equals(dynamicDataSource.getUrl())) { + if (dataSource.getUrl().equals(dynamicDataSource.getUrl()) + && dataSource.getTenantId().equals(dynamicDataSource.getTenantId())) { dataSourceList.remove(dataSource); - set(dataSource.getTenantId(), dataSourceList); break; } } } + set(dynamicDataSource.getTenantId(), dataSourceList); } /** @@ -99,11 +110,11 @@ public class BackupDatasourceContext { for (DynamicDataSource dynamicDataSource : dataSourceList) { if (dataSource.getDatasourceId().equals(dynamicDataSource.getDatasourceId())) { dataSourceList.remove(dynamicDataSource); - dataSourceList.add(dataSource); break; } } } + dataSourceList.add(dataSource); set(dataSource.getTenantId(), dataSourceList); } } diff --git a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/PrimaryDatasourceContext.java b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/PrimaryDatasourceContext.java index 57a44db..1c82175 100644 --- a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/PrimaryDatasourceContext.java +++ b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/context/PrimaryDatasourceContext.java @@ -60,4 +60,13 @@ public class PrimaryDatasourceContext { public static void remove(String tenantId) { PRIMARY_DATASOURCE_MAP.remove(tenantId); } + + /** + * 是否存在 + * + * @param tenantId 租户ID + */ + public static boolean exist(String tenantId) { + return PRIMARY_DATASOURCE_MAP.containsKey(tenantId); + } } diff --git a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/entity/DynamicDataSource.java b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/entity/DynamicDataSource.java index 6f61ff9..aa57ae9 100644 --- a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/entity/DynamicDataSource.java +++ b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/entity/DynamicDataSource.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; +import java.util.Objects; /** * 动态数据源实体 @@ -76,4 +77,5 @@ public class DynamicDataSource implements Serializable { * 服务器SN */ private String serverSn; + } diff --git a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java index 57a9b4c..50a9a18 100644 --- a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java +++ b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java @@ -142,10 +142,8 @@ public class OnlineDatasourceMonitor { return false; } - Integer backupIndex = null; - - for (int i = 0; i < dataSources.size(); i++) { - DynamicDataSource backDatasource = dataSources.get(i); + DynamicDataSource backDynamicDataSource = null; + for (DynamicDataSource backDatasource : dataSources) { Object dynamicDataSource = DatasourceUtil.buildDataSource(tenantId, backDatasource); // 不是空,说明备用数据源有用 if (Objects.nonNull(dynamicDataSource)) { @@ -154,23 +152,20 @@ public class OnlineDatasourceMonitor { redisService.convertAndSend("test", JSONUtil.toJsonStr(backDatasource)); // 延迟1s钟 等待其他服务器完成切换 ThreadUtil.sleep(1000); - backupIndex = i; + backDynamicDataSource = backDatasource; break; } } - - if (Objects.nonNull(backupIndex)) { - // 切换成功 - DynamicDataSource dynamicDataSource = dataSources.get(backupIndex); + // 切换成功 + if (Objects.nonNull(backDynamicDataSource)) { // 更改数据库中该数据源为主要数据源 - if (Objects.nonNull(dynamicDataSource.getTenantId()) && !TenantConstant.DEFAULT_TENANT_ID.equals(dynamicDataSource.getTenantId())) { + if (Objects.nonNull(backDynamicDataSource.getTenantId()) && !TenantConstant.DEFAULT_TENANT_ID.equals(backDynamicDataSource.getTenantId())) { // 添加到待处理任务中 - addWaitUpdateDatasourceStatus(dynamicDataSource.getTenantId(), dynamicDataSource.getDatasourceId()); + addWaitUpdateDatasourceStatus(backDynamicDataSource.getTenantId(), backDynamicDataSource.getDatasourceId()); } // 备用数据源集合删除该数据源 - dataSources.remove((int) backupIndex); - backupDatasourceContext.addBackupMap(tenantId, dataSources); - log.info("租户:[{}]切换备用数据源成功, 现主数据ID: {}", tenantId, dynamicDataSource.getDatasourceId()); + backupDatasourceContext.deleteBackupMap(backDynamicDataSource); + log.info("租户:[{}]切换备用数据源成功, 现主数据ID: {}", tenantId, backDynamicDataSource.getDatasourceId()); return true; } else { log.error("租户:[{}]切换备用数据源失败, 原因: 备用数据源均无效", tenantId); diff --git a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/util/JdbcUtil.java b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/util/JdbcUtil.java index a392760..cfaa484 100644 --- a/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/util/JdbcUtil.java +++ b/qiaoba-common/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/util/JdbcUtil.java @@ -32,6 +32,8 @@ public class JdbcUtil { Connection conn = null; try { Class.forName(driver); + // 设置两秒延时 默认10s + DriverManager.setLoginTimeout(2); //建立连接 conn = DriverManager.getConnection(url, username, password); return true; diff --git a/qiaoba-module/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/filter/DynamicDataSourceFilter.java b/qiaoba-module/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/filter/DynamicDataSourceFilter.java index 9c8805a..c76c01e 100644 --- a/qiaoba-module/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/filter/DynamicDataSourceFilter.java +++ b/qiaoba-module/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/filter/DynamicDataSourceFilter.java @@ -3,14 +3,17 @@ package com.qiaoba.module.tenant.filter; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.DateUtil; import com.qiaoba.api.tenant.entity.SysTenant; +import com.qiaoba.api.tenant.enums.TenantModeEnum; import com.qiaoba.api.tenant.enums.TenantStatusEnum; import com.qiaoba.api.tenant.utils.TenantUtil; +import com.qiaoba.common.base.code.DatasourceErrorCode; import com.qiaoba.common.base.code.TenantErrorCode; import com.qiaoba.common.base.constant.BaseConstant; import com.qiaoba.common.base.constant.TenantConstant; import com.qiaoba.common.base.context.BaseContext; import com.qiaoba.common.base.order.FilterOrder; import com.qiaoba.common.database.config.DynamicDataSourceConfig; +import com.qiaoba.common.database.context.PrimaryDatasourceContext; import com.qiaoba.common.web.util.ResponseUtil; import com.qiaoba.common.web.util.UriUtil; import com.qiaoba.module.tenant.service.SysTenantService; @@ -61,6 +64,7 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter { try { log.debug("Start run DynamicDataSourceFilter, Uri: {}", request.getRequestURI()); String tenantId = request.getHeader(TenantConstant.HEADER_KEY_TENANT); + // 主系统 or 登录入口获取租户列表 if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId) || TenantConstant.LOGIN_TENANT_LIST_URI.equals(request.getRequestURI())) { dynamicDataSourceConfig.setDefaultSetting(); @@ -113,6 +117,14 @@ public class DynamicDataSourceFilter extends OncePerRequestFilter { return true; } + // 检查租户数据源是否正常 + if (TenantModeEnum.isDatasource(sysTenant.getMode()) + && !PrimaryDatasourceContext.exist(sysTenant.getTenantId())) { + // 无主数据 + log.debug("租户数据源不可用, 租户ID: {}", sysTenant.getTenantId()); + ResponseUtil.errorAuth(response, DatasourceErrorCode.CONNECT_ERROR.getCode(), DatasourceErrorCode.CONNECT_ERROR.getMsg()); + return true; + } if (TenantStatusEnum.isDisable(sysTenant.getStatus())) { // 封禁状态 log.debug("租户已封禁, 租户ID: {}", sysTenant.getTenantId());