Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to preinitialize DBCP connection pool on startup?

The setup of my project is -

  1. Spring JDBC for persistence
  2. Apache DBCP 1.4 for connection pooling
  3. Mysql 5 on Linux

Here is the log of my application that captures the interactions with the database.

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

Two things are clear from the log -

  1. The connection pool only starts creating connections when the first request to execute a query is received.
  2. A pool of 4 connections takes nearly 30 seconds to initialize.

My questions are -

  1. How should one configure DBCP to initialize on startup automatically?
  2. Should it really take that long to create connections?

Note: Please don't suggest switching to C3P0 or Tomcat connection pool. I'm aware of those solutions. I'm more interested in understanding the problem at hand than just a quick fix. Besides I'm sure something so basic should be possible with DBCP as well.

Contents of 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>
like image 923
Kshitiz Sharma Avatar asked Jan 29 '13 10:01

Kshitiz Sharma


3 Answers

The initialSize doesn't take effect until you first request a connection. From the java docs to BasicDataSource#setInitialSize

Sets the initial size of the connection pool.

Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first time one of the following methods is invoked: getConnection, setLogwriter, setLoginTimeout, getLoginTimeout, getLogWriter.

Try adding init-method="getLoginTimeout" to your bean to confirm this.

like image 94
sbridges Avatar answered Nov 01 '22 12:11

sbridges


For a web application, you can implement ServletContextListener.contextInitialized() method and fire a test query (e.g. Select ID From Emp Limit 1) using your DataAccess layer. This should initialize your connection pool and make it ready before your application starts serving real user from web.

like image 34
Bimalesh Jha Avatar answered Nov 01 '22 14:11

Bimalesh Jha


Have a look at the initialSize property -especially the part about when the pool is initialized. As sbridges points out, you can use the init-method property on beans to call one of the methods to trigger pool creation.

Also, you should look into why it takes 7.5 seconds on average to create a connection...

Cheers,

like image 41
Anders R. Bystrup Avatar answered Nov 01 '22 13:11

Anders R. Bystrup