云环境SpringBoot自定义Oracle UCP数据源报连接池已存在错误求助
Oracle UCP连接池重复创建问题排查建议
问题描述
在云环境运行SpringBoot应用,执行数次数据库调用后遇到以下错误,本地无法复现:
Caused by: oracle.ucp.UniversalConnectionPoolException: Universal Connection Pool already exists in the Universal Connection Pool Manager. Universal Connection Pool cannot be added to the Universal Connection Pool Manager at oracle.ucp.util.UCPErrorHandler.newUniversalConnectionPoolException(UCPErrorHandler.java:378) at oracle.ucp.util.UCPErrorHandler.throwUniversalConnectionPoolException(UCPErrorHandler.java:68) at oracle.ucp.util.UCPErrorHandler.throwUniversalConnectionPoolException(UCPErrorHandler.java:91) at oracle.ucp.util.UCPErrorHandler.throwUniversalConnectionPoolException(UCPErrorHandler.java:149) at oracle.ucp.jdbc.PoolDataSourceImpl.createUniversalConnectionPool(PoolDataSourceImpl.java:985) ... 37 common frames omitted
背景信息
数据源Bean从已弃用的OracleDataSource (dataSource.setConnectionCachingEnabled(true))迁移而来,代码如下:
@Bean("testDataSource") DataSource getDataSource() throws SQLException { logger.info("Setting UP DataSource for : {}", DB_POOL_PROVIDER_UCP); PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource(); pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource"); pds.setURL(url); pds.setUser(username); pds.setPassword(password); pds.setConnectionPoolName("TestDBPool"); pds.setMinPoolSize(2); pds.setMaxPoolSize(50); pds.setInitialPoolSize(3); pds.setInactiveConnectionTimeout(60); pds.setMaxStatements(100); pds.setAbandonedConnectionTimeout(60); pds.setConnectionWaitTimeout(30); pds.setTimeToLiveConnectionTimeout(240); pds.setTimeoutCheckInterval(60); pds.setFastConnectionFailoverEnabled(false); //单节点部署 pds.setValidateConnectionOnBorrow(true); pds.setSQLForValidateConnection("select 1 from dual"); return pds; }
数据源主要用于org.springframework.jdbc.object.StoredProcedure和try (Connection conn = dataSource.getConnection())方式获取连接。
环境版本
- SpringBootVersion:3.3.0
- UCP:21.9.0.0
- ojdbc11:21.9.0.0
本地测试:启动应用调用随机API后,仅能获取到TestDBPool这一个连接池名称。
POM依赖片段
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc11</artifactId> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ucp</artifactId> </dependency>
排查方向与建议
- 确认Bean是否重复初始化:Spring Boot默认单例Bean,但如果存在多配置类、扫描范围异常或特殊类加载场景,可能导致
testDataSource被多次创建。可以在Bean方法中增加日志频次,观察是否多次输出"Setting UP DataSource for : UCP";也可以显式添加@Scope("singleton")声明,避免单例失效。 - 提前检查连接池是否存在:UCP的连接池名称全局唯一,可在创建池之前通过管理器检查,避免重复注册:
UniversalConnectionPoolManager ucpManager = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager(); if (ucpManager.getConnectionPool("TestDBPool") == null) { // 执行原有初始化逻辑 } else { logger.info("连接池TestDBPool已存在,直接复用"); return (PoolDataSource) ucpManager.getConnectionPool("TestDBPool").getDataSource(); } - 禁用Spring Boot自动数据源配置:引入
spring-boot-starter-data-jpa后,框架可能触发自动数据源配置逻辑。可在启动类添加@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HikariDataSourceAutoConfiguration.class}),确保只有自定义数据源生效。 - 排查云环境特殊机制:云环境可能存在应用热重启、实例伸缩、类加载器缓存等情况,导致连接池实例未正确销毁就被重新创建。检查应用启动日志,确认是否存在多次启动或类加载重复加载的现象。
- 验证版本兼容性:尝试升级UCP到最新稳定版本(如23.x系列),排查是否为旧版本的全局池注册bug。
- 检查连接泄漏问题:高并发下连接未正确释放可能导致池状态异常,触发重复创建逻辑。确保所有
Connection都通过try-with-resources管理,或显式调用close()方法释放。
内容的提问来源于stack exchange,提问作者Swaraj
相关产品推荐
相关产品推荐

