最近优化代码,发现第一次调用数据库连接时非常慢,往后便不再发生。经了解,数据库连接是用dbcp管理的,想在网上查找答案,但没有找到。在某人的提醒下决定研究源代码:
部分源代码如下(BasicDataSource.java):
protected volatile DataSource dataSource = null;
public Connection getConnection() throws SQLException {
return createDataSource().getConnection();
}
protected synchronized DataSource createDataSource()
throws SQLException {
if (closed) {
throw new SQLException("Data source is closed");
}
// Return the pool if we have already created it
if (dataSource != null) {
return (dataSource);
}
// create factory which returns raw physical connections
ConnectionFactory driverConnectionFactory = createConnectionFactory();
// create a pool for our connections
createConnectionPool();
// Set up statement pool, if desired
GenericKeyedObjectPoolFactory statementPoolFactory = null;
if (isPoolPreparedStatements()) {
statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
-1, // unlimited maxActive (per key)
GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
0, // maxWait
1, // maxIdle (per key)
maxOpenPreparedStatements);
}
// Set up the poolable connection factory
createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
// Create and return the pooling data source to manage the connections
createDataSourceInstance();
try {
for (int i = 0 ; i < initialSize ; i++) {
connectionPool.addObject();
}
} catch (Exception e) {
throw new SQLNestedException("Error preloading the connection pool", e);
}
return dataSource;
}
当我第一次们调用BasicDataSource的getConnection()方法时,需要先调用createDataSource()方法,该方法内有下面这一句:
// Return the pool if we have already created it
if (dataSource != null) {
return (dataSource);
}
而默认的dataSource是null
protected volatile DataSource dataSource = null;
所以,第一次调用getConnection()方法时,需要先创建dataSource实例,这个实例的创建非常费时间,就导致了我开始说的第一次调用数据库连接非常慢的问题了。那么该如何解决这个问题呢?
笔者想了两个方法,思路都是一样的,都是要在调用连接之前初始化好dataSource这个实例:
第一种,在调用连接之前先获取连接,然后将这个连接关掉,这样,就执行了dataSource的实例化;
第二种,写一个BasicDataSource的子类,用于代替BasicDataSource
public class BasicDataSourceSub extends BasicDataSource
{
public synchronized DataSource createDataSource()
{
try
{
return super.createDataSource();
}
catch (SQLException e)
{
throw new RuntimeException();
}
}
}
将原来protected synchronized DataSource createDataSource()方法变为共有的,在设置完dbcp的属性后执行这个方法,也会让dataSource实例化。
以上就是我对dbcp第一次获取连接时间的相关经验,如有不到之处,还请大家多多指教。