JUnit测试中Oracle UCP连接池启动失败,生产环境及主方法正常
Oracle UCP连接池JUnit测试启动失败问题解决
问题现象
初始化Oracle UCP连接池时,JUnit集成测试始终失败,但生产环境或单独main方法中使用相同配置启动连接池完全正常,所有场景连接属性一致。失败固定发生在this.universalConnectionPool.start();代码处。
报错栈信息
Caused by: com.xelog.nx.wms.hardware.hrl.HRLDriverException: java.lang.AssertionError: pool start procedure finished with wrong life cycle state, lifecycle=Starting at com.xelog.nx.wms.hardware.hrl.OracleConnectionProvider.<init>(OracleConnectionProvider.java:128) ... 72 more Caused by: java.lang.AssertionError: pool start procedure finished with wrong life cycle state, lifecycle=Starting at oracle.ucp.common.UniversalConnectionPoolBase.start(UniversalConnectionPoolBase.java:903) at oracle.ucp.jdbc.oracle.OracleJDBCConnectionPool.start(OracleJDBCConnectionPool.java:143) at oracle.ucp.jdbc.oracle.OracleReplayableConnectionConnectionPool.start(OracleReplayableConnectionConnectionPool.java:102) at oracle.ucp.UniversalConnectionPool.start(UniversalConnectionPool.java:224) ... 74 more
连接池实现代码
package com.test; import oracle.ucp.UniversalConnectionPool; import oracle.ucp.UniversalConnectionPoolAdapter; import oracle.ucp.UniversalConnectionPoolException; import oracle.ucp.UniversalConnectionPoolLifeCycleState; import oracle.ucp.admin.UniversalConnectionPoolManager; import oracle.ucp.admin.UniversalConnectionPoolManagerImpl; import oracle.ucp.jdbc.PoolDataSource; import oracle.ucp.jdbc.PoolDataSourceFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.sql.Connection; import java.sql.SQLException; import java.util.Map; import java.util.Properties; public class OracleConnectionProvider { private static final Logger LOG = LogManager.getLogger(OracleConnectionProvider.class); private static final long MAX_STARTUP_WAIT_MILLIS = 5000;//30000; private final String connectionFactory; private final String url; private final String user; private final String password; private final String connectionPoolName; private PoolDataSource pds; private UniversalConnectionPool universalConnectionPool; public OracleConnectionProvider(final String connectionFactory, final String url, final String user, final String password, final Map<String, String> propertyMap, final String poolName, final int minPoolSize, final int maxPoolSize) throws HRLDriverException { this.connectionFactory = connectionFactory; this.url = url; this.user = user; this.password = password; this.connectionPoolName = poolName; final long startOracleConnectionProvider = System.currentTimeMillis(); try { final UniversalConnectionPoolManager ucpManager = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager(); this.pds = PoolDataSourceFactory.getPoolDataSource(); this.pds.setConnectionPoolName(this.connectionPoolName); this.pds.setConnectionFactoryClassName(this.connectionFactory); this.pds.setURL(this.url); this.pds.setUser(this.user); this.pds.setPassword(this.password); this.pds.setValidateConnectionOnBorrow(true); this.pds.setInitialPoolSize(minPoolSize); this.pds.setMinPoolSize(minPoolSize); this.pds.setMaxPoolSize(maxPoolSize); // Default is 30secs. Set the frequency in seconds to enforce the timeout // properties. Applies to inactiveConnectionTimeout(int secs), // AbandonedConnectionTimeout(secs)& TimeToLiveConnectionTimeout(int secs). // Range of valid values is 0 to Integer.MAX_VALUE. . this.pds.setTimeoutCheckInterval(5); // Default is 0. Set the maximum time, in seconds, that a // connection remains available in the connection pool. this.pds.setInactiveConnectionTimeout(10); if (propertyMap != null && !propertyMap.isEmpty()) { final Properties properties = this.pds.getConnectionProperties(); properties.putAll(propertyMap); this.pds.setConnectionProperties(properties); } else { this.pds.setConnectionProperties(new Properties()); } if (!(this.pds instanceof UniversalConnectionPoolAdapter)) { LOG.info("Not expected implementation {}, pool sanity check not possible", UniversalConnectionPoolAdapter.class); } final UniversalConnectionPoolAdapter connectionPoolAdapter = (UniversalConnectionPoolAdapter) this.pds; connectionPoolAdapter.createUniversalConnectionPool(); this.universalConnectionPool = ucpManager.getConnectionPool(this.connectionPoolName); this.universalConnectionPool.start(); LOG.info("Startup - Initial"); UniversalConnectionPoolLifeCycleState loopLifeCycleState = UniversalConnectionPoolLifeCycleState.LIFE_CYCLE_STARTING; while ((System.currentTimeMillis() - startOracleConnectionProvider) < MAX_STARTUP_WAIT_MILLIS && loopLifeCycleState != UniversalConnectionPoolLifeCycleState.LIFE_CYCLE_RUNNING) { LOG.info("Startup - Waited {}ms not ready {}", System.currentTimeMillis() - startOracleConnectionProvider, loopLifeCycleState); loopLifeCycleState = this.universalConnectionPool.getLifeCycleState(); Thread.sleep(500); } final UniversalConnectionPoolLifeCycleState finalLifeCycleState = this.universalConnectionPool.getLifeCycleState(); if (finalLifeCycleState != UniversalConnectionPoolLifeCycleState.LIFE_CYCLE_RUNNING) { LOG.warn("Startup - Wrong State {}, max wait time of {}ms exceeded.", finalLifeCycleState, MAX_STARTUP_WAIT_MILLIS); } else { LOG.info("Startup - Successfully started within {}ms", System.currentTimeMillis() - startOracleConnectionProvider); } } catch (final InterruptedException e) { LOG.error("Error while initializing the data source, thread was interrupted", e); Thread.currentThread().interrupt(); } catch (final SQLException e) { LOG.error("Error while initializing the data source", e); throw new HRLDriverException(e); } catch (final UniversalConnectionPoolException e) { LOG.error("Error while initializing the universal connection pool manager.", e); throw new HRLDriverException(e); } catch (final Throwable e) { LOG.error("Error while initializing the driver.", e); throw new HRLDriverException(e); } } public Connection getConnection() throws SQLException { if(this.universalConnectionPool.getLifeCycleState() != UniversalConnectionPoolLifeCycleState.LIFE_CYCLE_RUNNING){ throw new SQLException("Pool is not running, state is " + this.universalConnectionPool.getLifeCycleState()); } return this.pds.getConnection(); } public void destroy() throws SQLException { if (this.pds != null) { this.pds.setInitialPoolSize(0); this.pds.setMinPoolSize(0); this.pds.setMaxPoolSize(0); final UniversalConnectionPoolLifeCycleState lifeCycleState = this.universalConnectionPool.getLifeCycleState(); try { if(lifeCycleState == UniversalConnectionPoolLifeCycleState.LIFE_CYCLE_STOPPED){ LOG.info("Connection pool is already in state {}", this.universalConnectionPool.getLifeCycleState()); } else { LOG.info("Connection pool try to purge with state {}", lifeCycleState); this.universalConnectionPool.purge(); LOG.info("Connection pool '{}' successfully purged final state {}", this.connectionPoolName, this.universalConnectionPool.getLifeCycleState()); } } catch (final UniversalConnectionPoolException e) { LOG.error("Connection pool {} purge failed with state {}",this.connectionPoolName, lifeCycleState, e); } catch (final Throwable e){ LOG.error("Connection pool {} purge failed with unknown error with state {}", this.connectionPoolName, lifeCycleState, e); } } } }
依赖差异分析
无法正常运行的依赖配置
<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>23.2.0.0</version> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ucp</artifactId> <version>23.2.0.0</version> </dependency>
可正常运行的依赖配置
<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8-production</artifactId> <version>23.2.0.0</version> <type>pom</type> </dependency> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ucp</artifactId> <version>23.2.0.0</version> </dependency>
原因与解决方案
单独引入ojdbc8时,缺少Oracle UCP连接池在JUnit测试环境启动所需的附属依赖(如oraclepki、osdt_core等),这些依赖是连接池完成生命周期切换(从Starting到Running)的必要组件。而ojdbc8-production是一个聚合POM,会自动引入ojdbc8及所有配套的依赖包,确保连接池启动时的依赖完整性。
解决方法:将单独的ojdbc8依赖替换为ojdbc8-production聚合POM,即可在JUnit测试中正常启动连接池。
内容的提问来源于stack exchange,提问作者eisentor
相关产品推荐
相关产品推荐

