Professional Documents
Culture Documents
by Kunal Jaggi
04/19/2006
Software object pooling is not a new concept. There are many scenarios where some type of object
pooling technique is employed to improve application performance, concurrency, and scalability. After
all, having your database code create a new Connection object on every client request is an
expensive process. Moreover, with today's demanding applications, creating new connections for data
access from scratch, maintaining them, and tearing down the open connection can lead to massive load
on the server.
Connection pooling eliminates JDBC overhead. Further, GS_googleAddAdSenseService("ca-pub-
object pooling also helps to reduce the garbage 4136420132070439");
collection load. In this article, we'll look at an elegant GS_googleEnableAllServices();GA_googleA
way of creating a pool of open database-connection ddSlot("ca-pub-4136420132070439",
objects in Tomcat, so that they are handy whenever an "OReillyNet_ROS_300x250");GA_googleFet
application needs to access a DB resource. chAds();GA_googleFillSlot("OReillyNet_RO
S_300x250");<!--
With Database Connection Pooling (DBCP), we can
google_ad_client = "pub-
scale our applications to handle increased load and
9073645249758045";
deliver high performance benefits. Using recycled
database connection objects cuts the time taken to re- /* O'Reilly_RON_300x250 */
google_ad_slot = "3840218845";
instantiate and load frequently used objects, thus
reducing unnecessary overheads. Configuring a DB pool google_ad_width = 300;
can be a daunting task, because there has to be a way for google_ad_height = 250;
//--
different components within an application to know
about the available pooled objects, and a mechanism to >google_protectAndRun("ads_core.google_re
locate them. This is exactly where JNDI steps in, tying nder_ad", google_handleError,
google_render_ad);
these dependencies together.
Tomcat Configuration
Our approach to DBCP uses the Jakarta-Commons database connection pool. But first, we need to
configure the JNDI DataSource in Tomcat by adding a declaration for the resource to server.xml
file, which resides inside the /conf directory of your Tomcat installation (indicated by the environment
variable CATALINA_HOME). The JNDI DataSource is used as a factory for connections. One of the
major advantages of using a configuration like this is that the characteristics of the pool can be changed
without affecting the application code. Our application's use of connection pooling is almost
transparent. The following code snippet shows us how to configure the container to enable connection
pooling.
<Context path="/dbcp" docBase="dbcp" debug="5"
reloadable="true" crossContext="true">
</Context>
We can configure a maximum number of DB connections in the pool. Make sure you choose a
maximum connection count large enough to handle all of your database connections--alternatively, you
can set 0 for no limit. Further, we can set the maximum number of idle database connections to be
retained in the pool. Set this value to -1 for no limit. The most optimal performance is attained when
the pool in its steady state contains just enough connections to service all concurrent connection
requests, without having to create new physical database connections at runtime. We can also specify
the maximum time (in milliseconds) to wait for a database connection to become available, which in
this example is 10 seconds. An exception is thrown if this timeout is exceeded. You can set this value
to -1 to wait indefinitely. Please make sure your connector driver, such as mysql.jar, is placed inside
the /common/lib directory of your Tomcat installation.
To achieve performance and high throughput, we also need to fine-tune the container to work under
heavy traffic. Here's how we'll configure the Connector element for the maxProcessors and
acceptCount parameters in the server.xml file:
<!-- Configuring the request and response endpoints -->
<Connector port="80" maxHttpHeaderSize="8192" maxProcessors="150"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="150"
connectionTimeout="20000" disableUploadTimeout="true" />
<listener>
<listener-class> com.onjava.dbcp.DBCPoolingListener</listener-class>
</listener>
<servlet>
<servlet-name> EnrolledStudents</servlet-name>
<servlet-class> com.onjava.dbcp.CourseEnrollmentServlet</servlet-class>
<load-on-startup> 1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> EnrolledStudents</servlet-name>
<url-pattern> /enrollment.do</url-pattern>
</servlet-mapping>
This binding is vendor-specific, and every container has its own mechanism for setting data sources.
Please note that this is just a declaration for dependency on an external resource, and doesn't create the
actual resource. Comprehending the tags is pretty straightforward: this indicates to the container that
the local reference name jdbc/TestDB should be set by the app deployer, and this should match with the
resource name, as declared in server.xml file.
GS_googleAddAdSenseService("ca-pub-
As an example, let's create a listener class to work with 4136420132070439");
GS_googleEnableAllServices();GA_googleA
the pool. Our listener class implements the
ServletContextListener interface; thus, it'll be ddSlot("ca-pub-4136420132070439",
"OReillyNet_ROS_300x250");GA_googleFet
initialized when the container starts and creates a
chAds();GA_googleFillSlot("OReillyNet_RO
ServletContext for this web app. Remember,
S_300x250");document.write('<scr'+'ipt
there's only one ServletContext per web app. Any language="javascript"
class implementing the ServletContextListener src="http://ad.doubleclick.net/adj/idgt.oreillyn
interface is initialized when the container starts. This etwork/home_above;net=idgt;u=,idgt-
early initialization cuts unnecessary overhead later, since45197881_1289834638,11a753ad2b8badd,pro
it's ideal to have a cached set of open database gramming,idgt.server_l;;sec=home;fold=abov
connection objects available when the container starts e;tile=2;sz=300x250;net=idgt;ord1=8866;cont
rather than waiting for a client request. Inside the x=programming;dc=w;btg=idgt.server_l;ord=
listener class, we'll do the necessary JNDI lookup and 2067262404834043.8?"></scr'+'ipt>');google_
then set the DataSource as a ServletContext protectAndRun("ads_core.google_render_ad",
attribute so that it's available to the entire web app. The google_handleError, google_render_ad);
following code snippet shows us how to extract
DataSource through a JNDI call:
public class DBCPoolingListener implements
ServletContextListener{
public void contextInitialized
(ServletContextEvent sce){
try {
// Obtain our environment naming context
Context envCtx = (Context) new InitialContext().
lookup("java:comp/env");
sce.getServletContext().setAttribute
("DBCPool", ds);
} catch(NamingException e){ e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent
sce){
}
}
The servlet is written to use either pooled or non-pooled database connections, depending on the query
string passed in its URL. The servlet fetches a pooled connection object using Tomcat DBCP, and non-
pooled connections directly from MySQL connector.
Here's an example of obtaining a Connection object. If the pooledConnection flag is set, it
simply calls getConnection() on the DataSource. If not, it manually creates a new
Connection object:
private synchronized Connection getConnection
(boolean pooledConnection)
throws SQLException {
if (pooledConnection) {
pooledCount++;
nonPooledCount++;
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost/dbcptest","kunal",
"java_facier");
return con; //return a newly created object
}
}
Having acquired a Connection, the servlet executes a simple join between the course and enrollment
tables, and then formats and outputs the results as HTML. The example uses PreparedStatement
to pre-compile SQL and run it repeatedly. This eliminates the tedious task of parsing and compiling the
SQL query on every client request. Pre-compilation improves performance and offers enhanced
security by preventing SQL injection attacks. For thread safety, we'll keep Connection,
PreparedStatement, and ResultSet as local variables inside of the doGet() method.
Connections issued from the JNDI DataSource factory will be returned to the pool when closed.
Clients use a connection pool by borrowing a connection object, using it, and then returning it to the
pool by closing it. We have to make sure that after we are done with the Connection, we close it. If
a Connection is not closed, it will never be returned to the pool and become available for reuse. Of
course, that would tie up resources. The finally block guarantees that used ResultSet,
PreparedStatement, and Connection objects are closed and prevents any connection pool
leaks, as shown below:
GS_googleAddAdSenseService("ca-pub-
4136420132070439");
finally { GS_googleEnableAllServices();GA_googleA
try {if (rs != null) rs.close();} catch ddSlot("ca-pub-4136420132070439",
(SQLException e) {} "OReillyNet_ROS_300x250");GA_googleFet
try {if (pstmt != null) pstmt.close();}
catch (SQLException e) {} chAds();GA_googleFillSlot("OReillyNet_RO
try {if (connection != null) S_300x250");document.write('<scr'+'ipt
connection.close();} catch (SQLException e) language="javascript"
{} src="http://ad.doubleclick.net/adj/idgt.oreillyn
}
etwork/home_above;net=idgt;u=,idgt-
48365826_1289834785,11a753ad2b8badd,ser
ver,;;sec=home;fold=above;tile=2;sz=300x25
Performance Measurement 0;net=idgt;ord1=431448;contx=server;dc=s;bt
Before our application hits the ground running, we g=;ord=6980051925381466?"></scr'+'ipt>');
would like to stress test the app, evaluate its
performance, and compare the results between the
cached set of pooled connection objects and the non-pooling alternative. For this, we'll rely on JMeter,
an open source tool for load testing with a drag-and-drop-style GUI. I have written a test plan for stress
testing the web app. I have set up JMeter to stimulate 50 concurrent users, accessing a common servlet
two times without any interval. The results are pretty apparent after looking at the JMeter graph results
shown in Figures 1 and 2, below.
Conclusion
Connection pooling is a technique used for sharing a cached set of open database connections among
several requesting clients. It doesn't require you to modify your code significantly; rather, it provides
enhanced performance benefits. Object pooling should be used with care. It does require additional
overhead for such tasks as managing the state of the object pool, issuing objects to the application, and
recycling used objects. Pooling is best suited for objects that have a short lifetime. If you are already
working in a rich Java EE environment, then most likely you would be using an out-of-box connection
pooling facility provided by your app server, and your applications' use of connection pooling is almost
transparent.
Resources
• Example source code used in this article
• Jakarta-Commons home
• Sun's JNDI tutorial
• Tomcat JNDI DataSource how-to document
• MySQL's official JDBC driver
• JDBC 2.0 tutorial
• Apache JMeter
• Creating a JMeter test plan
Kunal Jaggi is an independent Java consultant, primarily focused on enterprise solutions with Java-
based technologies.