最近优化代码,发现第一次调用数据库连接时非常慢,往后便不再发生。经了解,数据库连接是用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第一次获取连接时间的相关经验,如有不到之处,还请大家多多指教。