How to establish a connection pool in JDBC?
Asked Answered
C

13

126

Can anybody provide examples or links on how to establish a JDBC connection pool?

From searching google I see many different ways of doing this and it is rather confusing.

Ultimately I need the code to return a java.sql.Connection object, but I am having trouble getting started..any suggestions welcome.

Update: Doesn't javax.sql or java.sql have pooled connection implementations? Why wouldn't it be best to use these?

Chelyabinsk answered 14/5, 2010 at 14:55 Comment(3)
No, stock JDBC does not provide Connection pooling. You need a separate library for that. Most app servers and servlet containers have Connection pools included with them. Also, the JPA implementations typically provide implementations as well.Partee
An update for modern day Java users. JDBC 3.0+ (which I believe is used in Java 6?) has an implementation for pooled DB connections. Java 7 uses JDBC 4, and Java 8 JDBC 4.1.Monosome
Regarding the JDBC 3.0 API for connection pooling: progress.com/tutorials/jdbc/jdbc-jdbc-connection-poolingGenic
G
107

If you need a standalone connection pool, my preference goes to C3P0 over DBCP (that I've mentioned in this previous answer), I just had too much problems with DBCP under heavy load. Using C3P0 is dead simple. From the documentation:

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");

// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);

// The DataSource cpds is now a fully configured and usable pooled DataSource 

But if you are running inside an application server, I would recommend to use the built-in connection pool it provides. In that case, you'll need to configure it (refer to the documentation of your application server) and to retrieve a DataSource via JNDI:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Gandhi answered 14/5, 2010 at 15:56 Comment(4)
Ditto, that. I've been observing DBCP deadlocking under a load for years now. Version after version.Vereeniging
yeah but C3P0 also, I have had the best experience with BoneCPBhutan
Looks like BoneCP has been deprecated in favor of HikariCP. HikariCP is also mentioned in an answer below.Vargo
Too bad it is GPLAutomobile
E
21

HikariCP

It's modern, it's fast, it's simple. I use it for every new project. I prefer it a lot over C3P0, don't know the other pools too well.

Electroencephalograph answered 3/6, 2015 at 15:34 Comment(0)
G
19

Usually if you need a connection pool you are writing an application that runs in some managed environment, that is you are running inside an application server. If this is the case be sure to check what connection pooling facilities your application server providesbefore trying any other options.

The out-of-the box solution will be the best integrated with the rest of the application servers facilities. If however you are not running inside an application server I would recommend the Apache Commons DBCP Component. It is widely used and provides all the basic pooling functionality most applications require.

Gardenia answered 14/5, 2010 at 15:18 Comment(0)
A
18

Don't reinvent the wheel.

Try one of the readily available 3rd party components:

  • Apache DBCP - This one is used internally by Tomcat, and by yours truly.
  • c3p0

Apache DBCP comes with different example on how to setup a pooling javax.sql.DataSource. Here is one sample that can help you get started.

Abridgment answered 14/5, 2010 at 15:9 Comment(4)
It's called C3P0. It's by the way more performant than DBCP in multithreaded environments since DBCP locks access to a single thread.Trimeter
@BalusC. Thanks for correction, my disclecsia got the better of me. You can see that the link is correct. :)Abridgment
@Mudassir. I would recommend looking at a drop-in replacement for DBCP contributed to Tomcat from Spring -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/…. You don't need the whole Tomcat server to use it, just a single jar tomcat-jdbc. You can get it from Maven Central -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22 -> search.maven.org/…Abridgment
@AlexanderPogrebnyak: Thank you Alexander, thats nice of you. I'm planning to use CP in an Axis web service. Will think about your suggestion. – Mudassir 7 mins agoThallic
C
17

I would recommend using the commons-dbcp library. There are numerous examples listed on how to use it, here is the link to the move simple one. The usage is very simple:

 BasicDataSource ds = new BasicDataSource();
 ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
 ds.setUsername("scott");
 ds.setPassword("tiger");
 ds.setUrl(connectURI);
 ...
 Connection conn = ds.getConnection();

You only need to create the data source once, so make sure you read the documentation if you do not know how to do that. If you are not aware of how to properly write JDBC statements so you do not leak resources, you also might want to read this Wikipedia page.

Cotidal answered 14/5, 2010 at 15:10 Comment(2)
Does this actually create a connection pool?Chelyabinsk
@Chelyabinsk Sure! The javax.sql.DataSource interface's definition contains an implementation of "Connection pooling“. ( besides, I think you already know what a JDBC interface is )Folse
P
7

In the app server we use where I work (Oracle Application Server 10g, as I recall), pooling is handled by the app server. We retrieve a javax.sql.DataSource using a JNDI lookup with a javax.sql.InitialContext.

it's done something like this

try {     
   context = new InitialContext();
   jdbcURL = (DataSource) context.lookup("jdbc/CachedDS");
   System.out.println("Obtained Cached Data Source ");
}
catch(NamingException e)   
{  
    System.err.println("Error looking up Data Source from Factory: "+e.getMessage());
}

(We didn't write this code, it's copied from this documentation.)

Posen answered 14/5, 2010 at 15:44 Comment(0)
O
6

In late 2017 Proxool, BoneCP, C3P0, DBCP are mostly defunct at this time. HikariCP (created in 2012) seems promising, blows the doors off anything else I know of. http://www.baeldung.com/hikaricp

Proxool has a number of issues:
- Under heavy load can exceed max number of connections and not return below max
- Can manage to not return to min connections even after connections expire
- Can lock up the entire pool (and all server/client threads) if it has trouble connecting to the database during HouseKeeper thread (does not use .setQueryTimeout)
- HouseKeeper thread, while having connection pool lock for its process, requests the Prototyper thread to recreate connections (sweep) which can result in race condition/lockup. In these method calls the last parameter should always be sweep:false during the loop, only sweep:true below it.
- HouseKeeper only needs the single PrototypeController sweep at the end and has more [mentioned above]
- HouseKeeper thread checks for testing of connections before seeing what connections may be expired [some risk of testing expired connection that may be broken/terminated through other timeouts to DB in firewall, etc.]
- The project has unfinished code (properties that are defined but not acted upon)
- The Default max connection life if not defined is 4 hours (excessive)
- HouseKeeper thread runs every five seconds per pool (excessive)

You can modify the code and make these improvements. But as it was created in 2003, and updated in 2008, its lacking nearly 10 years of java improvements that solutions like hikaricp utilize.

Overmeasure answered 13/12, 2017 at 22:52 Comment(0)
S
5

Pool

  • Pooling Mechanism is the way of creating the Objects in advance. When a class is loaded.
  • It improves the application performance [By re using same object's to perform any action on Object-Data] & memory [allocating and de-allocating many objects creates a significant memory management overhead].
  • Object clean-up is not required as we are using same Object, reducing the Garbage collection load.

« Pooling [ Object pool, String Constant Pool, Thread Pool, Connection pool]

String Constant pool

  • String literal pool maintains only one copy of each distinct string value. which must be immutable.
  • When the intern method is invoked, it check object availability with same content in pool using equals method. « If String-copy is available in the Pool then returns the reference. « Otherwise, String object is added to the pool and returns the reference.

Example: String to verify Unique Object from pool.

public class StringPoolTest {
    public static void main(String[] args) { // Integer.valueOf(), String.equals()
        String eol = System.getProperty("line.separator"); //java7 System.lineSeparator();

        String s1 = "Yash".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1));
        String s2 = "Yas"+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2));
        String s3 = "Yas".intern()+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3));
        String s4 = "Yas"+"h";
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4));
    }
}

Connection pool using Type-4 Driver using 3rd party libraries[ DBCP2, c3p0, Tomcat JDBC]

Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora]. wiki

In Connection pool mechanism, when the class is loaded it get's the physical JDBC connection objects and provides a wrapped physical connection object to user. PoolableConnection is a wrapper around the actual connection.

  • getConnection() pick one of the free wrapped-connection form the connection objectpool and returns it.
  • close() instead of closing it returns the wrapped-connection back to pool.

Example: Using ~ DBCP2 Connection Pool with Java 7[try-with-resources]

public class ConnectionPool {
    static final BasicDataSource ds_dbcp2 = new BasicDataSource();
    static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource();
    static final DataSource ds_JDBC = new DataSource();

    static Properties prop = new Properties();
    static {
        try {
            prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties"));

            ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") );
            ds_dbcp2.setUrl( prop.getProperty("URL") );
            ds_dbcp2.setUsername( prop.getProperty("UserName") );
            ds_dbcp2.setPassword( prop.getProperty("Password") );
            ds_dbcp2.setInitialSize( 5 );

            ds_c3p0.setDriverClass( prop.getProperty("DriverClass") );
            ds_c3p0.setJdbcUrl( prop.getProperty("URL") );
            ds_c3p0.setUser( prop.getProperty("UserName") );
            ds_c3p0.setPassword( prop.getProperty("Password") );
            ds_c3p0.setMinPoolSize(5);
            ds_c3p0.setAcquireIncrement(5);
            ds_c3p0.setMaxPoolSize(20);

            PoolProperties pool = new PoolProperties();
            pool.setUrl( prop.getProperty("URL") );
            pool.setDriverClassName( prop.getProperty("DriverClass") );
            pool.setUsername( prop.getProperty("UserName") );
            pool.setPassword( prop.getProperty("Password") );
            pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle)

            pool.setInitialSize(5);
            pool.setMaxActive(3);
            ds_JDBC.setPoolProperties( pool );
        } catch (IOException e) {   e.printStackTrace();
        } catch (PropertyVetoException e) { e.printStackTrace(); }
    }

    public static Connection getDBCP2Connection() throws SQLException {
        return ds_dbcp2.getConnection();
    }

    public static Connection getc3p0Connection() throws SQLException {
        return ds_c3p0.getConnection();
    }

    public static Connection getJDBCConnection() throws SQLException {
        return ds_JDBC.getConnection();
    }
}
public static boolean exists(String UserName, String Password ) throws SQLException {
    boolean exist = false;
    String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
    try ( Connection connection = ConnectionPool.getDBCP2Connection();
          PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) {
        pstmt.setString(1, UserName );
        pstmt.setString(2, Password );

        try (ResultSet resultSet = pstmt.executeQuery()) {
            exist = resultSet.next(); // Note that you should not return a ResultSet here.
        }
    }
    System.out.println("User : "+exist);
    return exist;
}

jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName> jdbc:oracle:thin:@localhost:1521:myDBName jdbc:mysql://localhost:3306/myDBName

connectionpool.properties

URL         : jdbc:mysql://localhost:3306/myDBName
DriverClass : com.mysql.jdbc.Driver
UserName    : root
Password    :

Web Application: To avoid connection problem when all the connection's are closed[MySQL "wait_timeout" default 8 hours] in-order to reopen the connection with underlying DB.

You can do this to Test Every Connection by setting testOnBorrow = true and validationQuery= "SELECT 1" and donot use autoReconnect for MySQL server as it is deprecated. issue

===== ===== context.xml ===== =====
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for a web application -->
<Context>
    <Resource name="jdbc/MyAppDB" auth="Container" 
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        type="javax.sql.DataSource" 

        initialSize="5" minIdle="5" maxActive="15" maxIdle="10"

        testWhileIdle="true"
            timeBetweenEvictionRunsMillis="30000"

        testOnBorrow="true"
            validationQuery="SELECT 1"
            validationInterval="30000"


        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/myDBName" 
        username="yash" password="777"
    />
</Context>

===== ===== web.xml ===== =====
<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/MyAppDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
===== ===== DBOperations ===== =====
servlet «   init() {}
Normal call used by sevlet  « static {}

static DataSource ds;
static {
    try {
        Context ctx=new InitialContext();
        Context envContext = (Context)ctx.lookup("java:comp/env");
        ds  =   (DataSource) envContext.lookup("jdbc/MyAppDB");
    } catch (NamingException e) {   e.printStackTrace();    }
}

See these also:

Samuel answered 13/6, 2016 at 9:1 Comment(4)
In the String Constant pool example, I understand when you wrote "If String-copy is available[.equals()] in the Pool then returns the reference. « Otherwise, String object is added to the pool and returns the reference." But in the public class StringPoolTest just has 2 void methods so they don't return anything. Does that code actually go through the process of managing the string pool? It doesn't even seem to use any arguments.Backpedal
@Backpedal :- it is just to know the pool concept, for string pool verification i just used hashCode, identityHashCode methodes. modified the code...Samuel
Sorry, s1 is not defined?Backpedal
OK, just wanted to make sure I was seeing it all. I will work on that. What I will need to something closer to your ConnectionPool Class. Thanks so much.Backpedal
G
4

As answered by others, you will probably be happy with Apache Dbcp or c3p0. Both are popular, and work fine.

Regarding your doubt

Doesn't javax.sql or java.sql have pooled connection implementations? Why wouldn't it be best to use these?

They don't provide implementations, rather interfaces and some support classes, only revelant to the programmers that implement third party libraries (pools or drivers). Normally you don't even look at that. Your code should deal with the connections from your pool just as they were "plain" connections, in a transparent way.

Gourami answered 14/5, 2010 at 15:28 Comment(0)
M
4

Vibur DBCP is another library for that purpose. Several examples showing how to configure it for use with Hibernate, Spring+Hibernate, or programatically, can be found on its website: http://www.vibur.org/

Also, see the disclaimer here.

Macrography answered 11/2, 2014 at 15:13 Comment(0)
H
3

Apache Commons has a library for that purpose: DBCP. Unless you have strange requirements around your pools, I'd use a library as it's bound to be trickier and more subtle than you would hope.

Hyaloplasm answered 14/5, 2010 at 15:10 Comment(0)
W
1

You should consider using UCP. Universal Connection Pool (UCP) is a Java connection pool. It is a features rich connection pool and tightly integrated with Oracle's Real Application Clusters (RAC), ADG, DG databases.

Refer to this page for more details about UCP.

Wulfe answered 15/6, 2016 at 21:59 Comment(0)
A
0

MiniConnectionPoolManager is a one-java-file implementation, if you're looking for an embeddable solution and are not too concerned about performances (though I haven't tested it in that regard).

It is multi-licensed EPL, LGPL and MPL.

Its documentation also gives alternatives worth checking (on top of DBCP and C3P0):

Aguste answered 29/9, 2015 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.