fix: 优化了动态数据源配置

This commit is contained in:
tangwei 2026-09-08 10:36:24 +08:00
parent c1ede68b1a
commit d4992b9687
4 changed files with 281 additions and 100 deletions

View File

@ -3,6 +3,7 @@ package com.yfd.platform.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
/****************************** /******************************
@ -13,9 +14,9 @@ import java.util.Map;
public class DynamicDataSource extends AbstractRoutingDataSource { public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, DataSource> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource); super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources); super.setTargetDataSources(new HashMap<Object, Object>(targetDataSources));
super.afterPropertiesSet(); super.afterPropertiesSet();
} }

View File

@ -1,6 +1,9 @@
package com.yfd.platform.datasource; package com.yfd.platform.datasource;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -11,7 +14,10 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* 动态数据源配置支持 达梦(DM) Oracle 两种数据库每种各有主从(master/slave) * 动态数据源配置支持 达梦(DM) Oracle 两种数据库每种各有主从(master/slave)
* <p>
* 每个数据源可通过配置项 {@code spring.datasource.druid.<key>.enabled} 按需开启/关闭
* 关闭后不会创建对应的连接池也不会注册到路由数据源中
* *
* @author yfd * @author yfd
*/ */
@ -22,56 +28,68 @@ public class DynamicDataSourceConfig {
@Bean @Bean
@ConfigurationProperties("spring.datasource.druid.dm-master") @ConfigurationProperties("spring.datasource.druid.dm-master")
@ConditionalOnProperty(prefix = "spring.datasource.druid.dm-master", name = "enabled", havingValue = "true", matchIfMissing = true)
public DataSource dmMasterDataSource() { public DataSource dmMasterDataSource() {
DruidDataSource dataSource = new DruidDataSource(); return newDruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
} }
@Bean @Bean
@ConfigurationProperties("spring.datasource.druid.dm-slave") @ConfigurationProperties("spring.datasource.druid.dm-slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.dm-slave", name = "enabled", havingValue = "true", matchIfMissing = true)
public DataSource dmSlaveDataSource() { public DataSource dmSlaveDataSource() {
DruidDataSource dataSource = new DruidDataSource(); return newDruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
} }
// ==================== Oracle 数据源 ==================== // ==================== Oracle 数据源 ====================
@Bean @Bean
@ConfigurationProperties("spring.datasource.druid.oracle-master") @ConfigurationProperties("spring.datasource.druid.oracle-master")
@ConditionalOnProperty(prefix = "spring.datasource.druid.oracle-master", name = "enabled", havingValue = "true", matchIfMissing = true)
public DataSource oracleMasterDataSource() { public DataSource oracleMasterDataSource() {
DruidDataSource dataSource = new DruidDataSource(); return newDruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
} }
@Bean @Bean
@ConfigurationProperties("spring.datasource.druid.oracle-slave") @ConfigurationProperties("spring.datasource.druid.oracle-slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.oracle-slave", name = "enabled", havingValue = "true", matchIfMissing = true)
public DataSource oracleSlaveDataSource() { public DataSource oracleSlaveDataSource() {
DruidDataSource dataSource = new DruidDataSource(); return newDruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
} }
// ==================== 路由数据源 ==================== // ==================== 路由数据源 ====================
@Bean @Bean
@Primary @Primary
public DynamicDataSource dataSource(DataSource dmMasterDataSource, public DynamicDataSource dataSource(@Qualifier("dmMasterDataSource") ObjectProvider<DataSource> dmMaster,
DataSource dmSlaveDataSource, @Qualifier("dmSlaveDataSource") ObjectProvider<DataSource> dmSlave,
DataSource oracleMasterDataSource, @Qualifier("oracleMasterDataSource") ObjectProvider<DataSource> oracleMaster,
DataSource oracleSlaveDataSource) { @Qualifier("oracleSlaveDataSource") ObjectProvider<DataSource> oracleSlave) {
Map<Object, Object> targetDataSources = new HashMap<>(); Map<Object, DataSource> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceKeys.DM_MASTER, dmMasterDataSource); putIfPresent(targetDataSources, DataSourceKeys.DM_MASTER, dmMaster);
targetDataSources.put(DataSourceKeys.DM_SLAVE, dmSlaveDataSource); putIfPresent(targetDataSources, DataSourceKeys.DM_SLAVE, dmSlave);
targetDataSources.put(DataSourceKeys.ORACLE_MASTER, oracleMasterDataSource); putIfPresent(targetDataSources, DataSourceKeys.ORACLE_MASTER, oracleMaster);
targetDataSources.put(DataSourceKeys.ORACLE_SLAVE, oracleSlaveDataSource); putIfPresent(targetDataSources, DataSourceKeys.ORACLE_SLAVE, oracleSlave);
// 默认使用达梦主库
return new DynamicDataSource(dmMasterDataSource, targetDataSources); // 默认优先使用达梦主库若未开启则回退到任意一个已开启的数据源
DataSource defaultDataSource = dmMaster.getIfAvailable();
if (defaultDataSource == null) {
defaultDataSource = targetDataSources.values().stream().findFirst()
.orElseThrow(() -> new IllegalStateException("未开启任何数据源,请至少启用一个数据源"));
}
return new DynamicDataSource(defaultDataSource, targetDataSources);
}
private DruidDataSource newDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setConnectionErrorRetryAttempts(0);
return dataSource;
}
private void putIfPresent(Map<Object, DataSource> targetDataSources, String key, ObjectProvider<DataSource> provider) {
DataSource dataSource = provider.getIfAvailable();
if (dataSource != null) {
targetDataSources.put(key, dataSource);
}
} }
} }

View File

@ -1,72 +1,231 @@
server: server:
port: 8093 port: 8093
tomcat:
connection-timeout: 300000
max-swallow-size: 500MB
spring: spring:
#应用名称 #应用名称
application: application:
name: Project-plateform name: Project-plateform
datasource: datasource:
type: com.alibaba.druid.pool.DruidDataSource type: com.alibaba.druid.pool.DruidDataSource
druid: druid:
# ==================== 达梦(DM) 数据源 ==================== # ==================== 达梦(DM) 数据源 ====================
dm-master: dm-master:
driverClassName: dm.jdbc.driver.DmDriver driverClassName: dm.jdbc.driver.DmDriver
url: "${DB_DM_MASTER_URL:jdbc:dm://localhost:5236/WPPDB}" url: "${DB_DM_MASTER_URL:jdbc:dm://172.16.21.143:5236/QGC_REFA_TEST}"
username: "${DB_DM_MASTER_USERNAME:WPPDB}" username: "${DB_DM_MASTER_USERNAME:QGC_REFA_TEST}"
password: "${DB_DM_MASTER_PASSWORD:}" password: "${DB_DM_MASTER_PASSWORD:Y4M4K1oCkL8U}"
dm-slave: initial-size: 5
driverClassName: dm.jdbc.driver.DmDriver min-idle: 5
url: "${DB_DM_SLAVE_URL:jdbc:dm://localhost:5236/WPPDB}" max-active: 50
username: "${DB_DM_SLAVE_USERNAME:WPPDB}" max-wait: 60000
password: "${DB_DM_SLAVE_PASSWORD:}" async-init: true
# ==================== Oracle 数据源 ==================== keep-alive-between-time-millis: 120000
oracle-master: time-between-eviction-runs-millis: 60000
driverClassName: oracle.jdbc.OracleDriver min-evictable-idle-time-millis: 180000
url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@localhost:1521/ORCL}" max-evictable-idle-time-millis: 300000
username: "${DB_ORACLE_MASTER_USERNAME:}" phy-timeout-millis: 25200000
password: "${DB_ORACLE_MASTER_PASSWORD:}" validation-query: SELECT 1 FROM DUAL
connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 validation-query-timeout: 3
oracle-slave: test-while-idle: true
driverClassName: oracle.jdbc.OracleDriver test-on-borrow: false
url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@localhost:1521/ORCL}" test-on-return: false
username: "${DB_ORACLE_SLAVE_USERNAME:}" keep-alive: true
password: "${DB_ORACLE_SLAVE_PASSWORD:}" remove-abandoned: true
connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 remove-abandoned-timeout: 1800
log-abandoned: true
mvc: break-after-acquire-failure: true
pathmatch: time-between-connect-error-millis: 30000
matching-strategy: ant_path_matcher pool-prepared-statements: true
data: max-open-prepared-statements: 100
redis: max-pool-prepared-statement-per-connection-size: 100
host: ${REDIS_HOST:localhost} dm-slave:
port: ${REDIS_PORT:6379} driverClassName: dm.jdbc.driver.DmDriver
password: ${REDIS_PASSWORD:} url: "${DB_DM_SLAVE_URL:jdbc:dm://172.16.21.143:5236/QGC_REFA_TEST}"
timeout: 10000ms username: "${DB_DM_SLAVE_USERNAME:QGC_REFA_TEST}"
lettuce: password: "${DB_DM_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
pool: initial-size: 5
max-active: 8 min-idle: 5
max-idle: 8 max-active: 50
min-idle: 2 max-wait: 60000
max-wait: 10000ms async-init: true
servlet: keep-alive-between-time-millis: 120000
multipart: time-between-eviction-runs-millis: 60000
max-file-size: 300MB min-evictable-idle-time-millis: 180000
max-request-size: 500MB max-evictable-idle-time-millis: 300000
file-size-threshold: 1KB phy-timeout-millis: 25200000
location: /tmp/upload validation-query: SELECT 1 FROM DUAL
resolve-lazily: true validation-query-timeout: 3
test-while-idle: true
test-on-borrow: false
test-on-return: false
keep-alive: true
remove-abandoned: true
remove-abandoned-timeout: 1800
log-abandoned: true
break-after-acquire-failure: true
time-between-connect-error-millis: 30000
pool-prepared-statements: true
max-open-prepared-statements: 100
max-pool-prepared-statement-per-connection-size: 100
# ==================== Oracle 数据源 ====================
# enabled=false 时不创建连接池,也不注册到路由数据源(按需开启)
oracle-master:
enabled: false
driverClassName: oracle.jdbc.OracleDriver
url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}"
username: "${DB_ORACLE_MASTER_USERNAME:SDLY_QX}"
password: "${DB_ORACLE_MASTER_PASSWORD:jNHnqv3hH7}"
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 30000
async-init: true
keep-alive-between-time-millis: 120000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 180000
max-evictable-idle-time-millis: 300000
phy-timeout-millis: 25200000
validation-query: SELECT 1 FROM DUAL
validation-query-timeout: 3
test-while-idle: true
test-on-borrow: false
test-on-return: false
keep-alive: true
remove-abandoned: true
remove-abandoned-timeout: 1800
log-abandoned: true
break-after-acquire-failure: true
time-between-connect-error-millis: 30000
pool-prepared-statements: true
max-open-prepared-statements: 100
max-pool-prepared-statement-per-connection-size: 100
connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000
oracle-slave:
enabled: false
driverClassName: oracle.jdbc.OracleDriver
url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}"
username: "${DB_ORACLE_SLAVE_USERNAME:SDLY_QX}"
password: "${DB_ORACLE_SLAVE_PASSWORD:jNHnqv3hH7}"
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 30000
async-init: true
keep-alive-between-time-millis: 120000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 180000
max-evictable-idle-time-millis: 300000
phy-timeout-millis: 25200000
validation-query: SELECT 1 FROM DUAL
validation-query-timeout: 3
test-while-idle: true
test-on-borrow: false
test-on-return: false
keep-alive: true
remove-abandoned: true
remove-abandoned-timeout: 1800
log-abandoned: true
break-after-acquire-failure: true
time-between-connect-error-millis: 30000
pool-prepared-statements: true
max-open-prepared-statements: 100
max-pool-prepared-statement-per-connection-size: 100
connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000
filter:
stat:
enabled: true
log-slow-sql: true
slow-sql-millis: 3000
merge-sql: true
slf4j:
enabled: true
wall:
enabled: true
log-violation: true
throw-exception: true
config:
select-where-alway-true-check: true
select-having-alway-true-check: true
delete-where-alway-true-check: true
update-where-alay-true-check: true
update-where-alway-true-check: true
update-where-none-check: true
multi-statement-allow: false
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*'
session-stat-enable: true
principal-session-name: admin
profile-enable: true
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
reset-enable: false
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mvc:
pathmatch:
matching-strategy: ant_path_matcher
data:
redis:
# host: "${REDIS_HOST:172.16.21.142}"
host: "${REDIS_HOST:localhost}"
port: "${REDIS_PORT:6379}"
password: "${REDIS_PASSWORD:}"
# password: "${REDIS_PASSWORD:zny5678}"
database: "${REDIS_DATABASE:15}"
timeout: 10000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 2
max-wait: 10000ms
servlet:
multipart:
max-file-size: 300MB
max-request-size: 500MB
file-size-threshold: 1KB
location: /tmp/upload
resolve-lazily: true
logging: logging:
file: file:
name: logs/projectname.log name: logs/platform-dev.log
level: level:
com.genersoft.iot: debug root: info
com.genersoft.iot.vmp.storager.dao: info com.yfd.platform: info
com.genersoft.iot.vmp.gb28181: info com.yfd.platform.common.MicroservicDynamicSQLMapper: info
# ... existing code ...
# com.yfd.platform.*.mapper: trace
# 在线文档: swagger-ui生产环境建议关闭 # 在线文档: swagger-ui生产环境建议关闭
swagger-ui: swagger-ui:
enabled: true enabled: true
mybatis-plus:
# mapper-locations: classpath*:**/mapper/*Mapper.xml,classpath*:**/mapping/*Mapper.xml
global-config:
banner: false
db-config:
id-type: ASSIGN_ID
insert-strategy: not_null
update-strategy: not_null
select-strategy: not_empty
table-underline: true
logic-delete-value: 1
logic-not-delete-value: 0
logic-delete-field: isDeleted
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 登录相关配置 # 登录相关配置
@ -84,7 +243,7 @@ login:
app: app:
# ZIP导入临时目录配置 # ZIP导入临时目录配置
zip-import: zip-import:
temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\qgc-platform\zip_import_temp} temp-dir: ${ZIP_IMPORT_TEMP_DIR:/qgc-platform/tmp/zip_import_temp}
init: init:
enabled: false enabled: false
schema: classpath:db-init/sql/min-schema.sql schema: classpath:db-init/sql/min-schema.sql
@ -111,8 +270,8 @@ ip:
file-space: #项目文档空间 file-space: #项目文档空间
files: D:\qgc-platform\files\ #单独上传的文件附件 files: /qgc-platform/files/ #单独上传的文件附件
system: D:\qgc-platform\system\ #单独上传的文件 system: /qgc-platform/system/ #单独上传的文件
task: task:
pool: pool:
@ -129,4 +288,4 @@ attachment:
token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH} token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH}
upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload} upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload}
video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload} video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload}
delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete} delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete}

View File

@ -18,8 +18,8 @@ spring:
password: "${DB_DM_MASTER_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_DM_MASTER_PASSWORD:Y4M4K1oCkL8U}"
initial-size: 5 initial-size: 5
min-idle: 5 min-idle: 5
max-active: 20 max-active: 50
max-wait: 30000 max-wait: 60000
async-init: true async-init: true
keep-alive-between-time-millis: 120000 keep-alive-between-time-millis: 120000
time-between-eviction-runs-millis: 60000 time-between-eviction-runs-millis: 60000
@ -47,8 +47,8 @@ spring:
password: "${DB_DM_SLAVE_PASSWORD:Y4M4K1oCkL8U}" password: "${DB_DM_SLAVE_PASSWORD:Y4M4K1oCkL8U}"
initial-size: 5 initial-size: 5
min-idle: 5 min-idle: 5
max-active: 20 max-active: 50
max-wait: 30000 max-wait: 60000
async-init: true async-init: true
keep-alive-between-time-millis: 120000 keep-alive-between-time-millis: 120000
time-between-eviction-runs-millis: 60000 time-between-eviction-runs-millis: 60000
@ -70,7 +70,9 @@ spring:
max-open-prepared-statements: 100 max-open-prepared-statements: 100
max-pool-prepared-statement-per-connection-size: 100 max-pool-prepared-statement-per-connection-size: 100
# ==================== Oracle 数据源 ==================== # ==================== Oracle 数据源 ====================
# enabled=false 时不创建连接池,也不注册到路由数据源(按需开启)
oracle-master: oracle-master:
enabled: false
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}"
username: "${DB_ORACLE_MASTER_USERNAME:SDLY_QX}" username: "${DB_ORACLE_MASTER_USERNAME:SDLY_QX}"
@ -101,6 +103,7 @@ spring:
max-pool-prepared-statement-per-connection-size: 100 max-pool-prepared-statement-per-connection-size: 100
connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000
oracle-slave: oracle-slave:
enabled: false
driverClassName: oracle.jdbc.OracleDriver driverClassName: oracle.jdbc.OracleDriver
url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}"
username: "${DB_ORACLE_SLAVE_USERNAME:SDLY_QX}" username: "${DB_ORACLE_SLAVE_USERNAME:SDLY_QX}"