当我的 java 应用程序几个小时没有对数据库的请求时,我收到过时的连接错误。
它是一个简单的Java应用程序,运行在带有OCI(类型驱动程序)的Linux盒子上。不要问我为什么OCI,为什么不瘦。我正在使用OracleDataSource
和OracleConnectionCacheManager
来维护连接对象的缓存。以下是代码片段:
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.pool.OracleConnectionCacheManager;
import oracle.jdbc.pool.OracleDataSource;
import org.apache.log4j.Logger;
import com.exception.DataException;
public class ConnectionManager {
private static OracleDataSource poolDataSource = null;
private final static String CACHE_NAME = "CONNECTION_POOL_CACHE";
private static OracleConnectionCacheManager occm = null;
public static void init(String url,String userId,String password) throws PCTDataException{
Properties cacheProps = null;
try {
poolDataSource = new OracleDataSource();
poolDataSource.setURL(url);
poolDataSource.setUser(userId);
poolDataSource.setPassword(password);
cacheProps = new Properties();
cacheProps.setProperty("MinLimit", "1");
cacheProps.setProperty("MaxLimit", "5");
cacheProps.setProperty("InitialLimit", "1");
cacheProps.setProperty("ValidateConnection", "true");
poolDataSource.setConnectionCachingEnabled(true);
occm = OracleConnectionCacheManager.getConnectionCacheManagerInstance();
occm.createCache(CACHE_NAME, poolDataSource, cacheProps);
occm.enableCache(CACHE_NAME);
} catch (SQLException se) {
throw new DataException("SQL Exception while initializing connection pool");
}catch(Exception e){
throw new DataException("Exception while initializing connection pool");
}
}
public static Connection getConnection() throws PCTDataException {
try{
if (poolDataSource == null) {
throw new SQLException("OracleDataSource is null.");
}
occm.refreshCache(CACHE_NAME, OracleConnectionCacheManager.REFRESH_INVALID_CONNECTIONS);
Connection connection = poolDataSource.getConnection();
return connection;
}catch(SQLException se){
se.printStackTrace();
throw new DataException("Exception while getting Connection object");
}catch(Exception e){
e.printStackTrace();
throw new DataException("Exception while getting Connection object");
}
}
public static void closePooledConnections() {
try{
if (poolDataSource != null) {
poolDataSource.close();
}
}catch(SQLException se){
}catch(Exception e){
}
}
}
错误如下:
ConnectionManager.java:getConnection:87 - Exception while getting Connection object:
java.sql.SQLException: Invalid or Stale Connection found in the Connection Cache
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at oracle.jdbc.pool.OracleImplicitConnectionCache.getConnection(OracleImplicitConnectionCache.java:390)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:404)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:189)
我错过了什么?
也许您需要设置保持活动状态? 这样做是定期的,不使用时它会向数据库服务器发送一个ping,基本上说我还在这里,不要关闭我。 不过,尝试调试并不是那么有趣。 问题可能是数据库服务器上的设置,其中存在最大连接年限,或者终止空闲连接的时间。池中也可能有一些设置,您可以使用这些设置来检查这一点,然后在发生这种情况时告诉它获取一个新设置。 我希望我能提供更多帮助,但我没有使用过甲骨文。
OracleDataSource + OracleConnectionCacheManager,我建议使用 OracleOCIConnectionPool,它是专门为缓存 OCI 连接而设计的。
它是OracleDataSource的替代品,除了OracleDataSource和OracleOCIConnectionPool的PoolConfig属性略有不同。
当您的连接池中有一个连接不再主动连接到数据库时,您将收到"无效或过时的连接"错误。以下是可能导致这种情况的几种情况
- 连接由 dba 从数据库中手动中止。例如,如果使用"更改系统终止会话"终止连接
- 当连接池中存在连接而不用于时间长,由于数据库 (idle_time)
- 数据库重新启动
- 网络事件导致连接断开,可能是因为网络已成为不可用或防火墙已断开连接打开时间过长。
运行以下查询以确定数据库强制实施的IDLE_TIME
select * from dba_profiles dp, dba_users du
where dp.profile = du.profile and du.username ='YOUR_JDBC_USER_NAME';
现在尝试使用以下配置
Properties cacheProps = new Properties();
cacheProps.setProperty("MinLimit", "0");
cacheProps.setProperty("MaxLimit", "5");
cacheProps.setProperty("InitialLimit", "1");
cacheProps.setProperty("ValidateConnection", "true");
cacheProps.setProperty("InactivityTimeout", "17000"); //something lower than the DB IDLE_TIME
cacheProps.setProperty("PropertyCheckInterval", "16000") /*something lower than the inactivity timeout
- to make sure that connections which were inactive for more than InactivityTimeout
are always removed from the pool*/