简体   繁体   中英

Connection pooling in java using c3p0

I want to using c3p0 for connection pooling in none-web application java program that i wrote. I used traditional singleton connection and I am not satisfied with its performance, so I decided to go for connection pooling. I take a look at c3p0 website and here is what they told about using c3p0:

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

I want to know how could i use that for ms sql windows authentication connection, but I could not figure it how? Also how can I set my query through that connection? It seems that using connection pooling is a whole different world than traditional database connection and I am new to that. Here is what i figure out:

public class DatabaseManager {

    private static DataSource dataSource;
    private static final String DRIVER_NAME;
    private static final String URL;
    private static final String UNAME;
    private static final String PWD;
    private static final String dbName;

    static {

        dbName="SNfinal";
        DRIVER_NAME = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
        URL = "jdbc:sqlserver://localhost:1433;" +
                      "databaseName="+dbName+";integratedSecurity=true";
        UNAME = "";
        PWD = "";
        dataSource = setupDataSource();
    }
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    private static DataSource setupDataSource() {
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        try {
            cpds.setDriverClass(DRIVER_NAME);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        cpds.setJdbcUrl(URL);
        cpds.setUser(UNAME);
        cpds.setPassword(PWD);
        cpds.setMinPoolSize(1000);
        cpds.setAcquireIncrement(1000);
        cpds.setMaxPoolSize(20000);
        return cpds;
    }
    public static ResultSet executeQuery(String SQL, String dbName)
    {
        ResultSet rset = null ;

        try {
            Connection con=DatabaseManager.getConnection();
               Statement st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
               rset = st.executeQuery(SQL);

        }
        catch (SQLException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }

        return rset;
     }

    public static void executeUpdate(String SQL, String dbName)
    {

        try {
            Connection con=DatabaseManager.getConnection();
               Statement st = con.createStatement();
               st.executeUpdate(SQL);

        }

        catch (SQLException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }
     }

}

When I use this class it works well for around 2000 queries, after that it stop working with some exceptions related to resource allocation!

if you are evolving an application from using a single cached Connection to using a Connection pool, the main thing you have to do is...

1) do not store any Connections as static or member variables of objects. store only a reference to the DataSource, cpds is the code sample above;

2) each time you need to use a Connection, call getConnection() on the the pool-backed DataSource;

3) be sure to close() the Connection after each use, reliably (ie in a finally block with each resource close wrapped in its own try/catch or, if your codebase is Java 7, via try-with-resources ). if you don't, you'll eventually leak Connections and exhaust the pool. c3p0 has some hacks to help you with that , but the best advice is not to write leaky code.

however you authenticate to acquire a single Connection should be how you authenticate via the pool. do you have to do something special or unusual to authenticate in your environment?


So, big big problems.

First some odds and ends: System.exit(0) is a bad way to respond to Exceptions. Your methods accept a dbName parameter that has no function.

But the big, huge, bad problem is that you do no resource cleanup whatsoever. Your executeQuery and executeUpdate methods open Connections and then fail to close() them. That will lead to resource leaks in short order. If you want to open Connection inside methods like these, you have to return them in some manner so that they can be close()ed after use. That will get cumbersome. You can redefine the methods to accept Connecion objects, that is, something like...

ResultSet executeQuery( Connection con, String query ) { 
  ...
}

...or better yet, just let your clients use the JDBC api directly, which will in fact be much simpler than using your execute methods that in fact do very little.

If you're codebase is Java 7, try-with-resources is a convenient way to ensure JDBC resources are cleaned up. If not, you'll have to use explicit finally clauses (with the calls to close() inside finally nested in their own try/catches).

As for the Exceptions you're seeing, their messages are pretty clear about the cause. You are using ResultSets after they have been close()ed. The question is why. I don't have a simple answer, but in general you are not being very clean about resource clean-up; I suspect that is the problem. I'm surprised you manage to get 2000 queries to ever run with this code, since you are leaking Connections and should have run out. So there are some mysteries. But one way or another, you are occasionally trying to use ResultSets after they have been close()ed, probably by some other Thread. Maybe you are doing something non-obvious to close() Connections, like using resultSet.getStatement(),getConnection() to find the resource you need to close(), and then close()ing the Connection before you've finished working with the ResultSet?

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM