如何在启动时预初始化 DBCP 连接池?

5

我项目的设置是 -

  1. 使用 Spring JDBC 进行持久化
  2. 使用 Apache DBCP 1.4 进行连接池管理
  3. 在 Linux 上使用 Mysql 5 数据库

这是我的应用程序日志,记录了与数据库的交互。

2013-01-29 15:52:21,549 DEBUG http-bio-8080-exec-3 org.springframework.jdbc.core.JdbcTemplate - Executing SQL query [SELECT id from emp]
2013-01-29 15:52:21,558 DEBUG http-bio-8080-exec-3 org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
2013-01-29 15:52:31,878  INFO http-bio-8080-exec-3 jdbc.connection - 1. Connection opened  org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
2013-01-29 15:52:31,878 DEBUG http-bio-8080-exec-3 jdbc.connection - open connections:  1 (1)
2013-01-29 15:52:31,895  INFO http-bio-8080-exec-3 jdbc.connection - 1. Connection closed  org.apache.commons.dbcp.DelegatingConnection.close(DelegatingConnection.java:247)
2013-01-29 15:52:31,895 DEBUG http-bio-8080-exec-3 jdbc.connection - open connections:  none
2013-01-29 15:52:41,950  INFO http-bio-8080-exec-3 jdbc.connection - 2. Connection opened  org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
2013-01-29 15:52:41,950 DEBUG http-bio-8080-exec-3 jdbc.connection - open connections:  2 (1)
2013-01-29 15:52:52,001  INFO http-bio-8080-exec-3 jdbc.connection - 3. Connection opened  org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
2013-01-29 15:52:52,002 DEBUG http-bio-8080-exec-3 jdbc.connection - open connections:  2 3 (2)
2013-01-29 15:53:02,058  INFO http-bio-8080-exec-3 jdbc.connection - 4. Connection opened  org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
2013-01-29 15:53:02,058 DEBUG http-bio-8080-exec-3 jdbc.connection - open connections:  2 3 4 (3)
2013-01-29 15:53:03,403 DEBUG http-bio-8080-exec-3 org.springframework.jdbc.core.BeanPropertyRowMapper - Mapping column 'id' to property 'id' of type int
2013-01-29 15:53:04,494 DEBUG http-bio-8080-exec-3 org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource

从日志中可以清楚地看到两件事情:
  1. 当收到第一个查询请求时,连接池才开始创建连接。
  2. 一个包含4个连接的连接池需要近30秒的时间来初始化。
我的问题是:
  1. 如何配置DBCP以在启动时自动初始化?
  2. 创建连接真的需要那么长时间吗?
注意:请不要建议切换到C3P0或Tomcat连接池。我知道这些解决方案。我更感兴趣的是理解手头的问题而不仅仅是快速修复。 此外,我相信使用DBCP也应该有可能实现如此基本的功能。
dbcontext的内容为:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.driver}" />
    <property name="url" value="${db.jdbc.url}" />
    <property name="username" value="${db.user}" />
    <property name="password" value="${db.password}" />
    <property name="maxActive" value="20" />
    <property name="initialSize" value="4" />
    <property name="testOnBorrow" value="true" />
    <property name="validationQuery" value="SELECT 1" />
</bean>

你试过禁用testOnBorrow后的性能差异吗?无论如何,我不相信使用C3P0创建连接是瞬间完成的……创建连接是耗时的,因此需要连接池。也许你只是测试方法不对,差异并没有那么大呢? - JanM
3个回答

6

只有在您首次请求连接时,initialSize 才会生效。请参考 Java 文档中的BasicDataSource#setInitialSize

设置连接池的初始大小。

注意:一旦池已初始化,此方法目前不起作用。当调用以下方法之一时,池将被初始化:getConnection、setLogwriter、setLoginTimeout、getLoginTimeout 或 getLogWriter。

为了确认这一点,请将 init-method="getLoginTimeout" 添加到您的 bean 中。


3

对于 Web 应用程序,您可以实现 ServletContextListener.contextInitialized() 方法,并使用您的数据访问层触发一个测试查询(例如:Select ID From Emp Limit 1)。这将初始化您的连接池并在您的应用程序开始为 Web 的真实用户提供服务之前使其准备就绪。


2
请查看initialSize属性,特别是关于池初始化的部分。正如sbridges所指出的那样,您可以在bean上使用init-method属性调用其中一个方法来触发池创建。
此外,您应该研究一下为什么平均需要7.5秒才能创建一个连接...
干杯,

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接