使用c3p0在java中连接池

时间:2013-12-21 05:59:28

标签: java connection-pooling c3p0

我想在我编写的非Web应用程序java程序中使用c3p0进行连接池。我使用传统的单例连接,我对它的性能不满意,所以我决定去连接池。我看看c3p0网站,以下是他们对使用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

我想知道我怎样才能将它用于ms sql windows身份验证连接,但我无法弄清楚如何?另外如何通过该连接设置查询?似乎使用连接池是一个完全不同于传统数据库连接的世界,我是新手。 以下是我的想法:

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);
        }
     }

}

当我使用这个类时,它适用于大约2000个查询,之后它停止处理与资源分配相关的一些例外!

1 个答案:

答案 0 :(得分:2)

如果您正在将应用程序从使用单个缓存连接演变为使用连接池,那么您需要做的主要是......

1)不要将任何Connections存储为对象的静态或成员变量。只存储对DataSource的引用,cpds是上面的代码示例;

2)每次需要使用Connection时,在池支持的DataSource上调用getConnection();

3)确保在每次使用后可靠地关闭()Connection(即在每个资源关闭包含在其自己的try / catch中的finally块中,或者如果您的代码库是Java 7,则通过{{ 3}})。如果你不这样做,你最终会泄漏连接并耗尽池。 c3p0有一些try-with-resources,但最好的建议是不要写漏洞代码。

但是,您要获取单个连接的身份验证应该是您通过池进行身份验证的方式。您是否需要在您的环境中做一些特殊或不寻常的认证?


所以,大问题。

首先是一些可能的结果:System.exit(0)是一种回应异常的坏方法。您的方法接受没有功能的dbName参数。

但是,一个巨大的,巨大的,糟糕的问题是你没有做任何资源清理。您的executeQueryexecuteUpdate方法打开了Connections,然后无法关闭()它们。这将导致短期内的资源泄漏。如果要在这些方法中打开Connection,则必须以某种方式返回它们,以便在使用后可以将它们关闭()。那会很麻烦。您可以重新定义接受Connecion对象的方法,例如......

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

......或者更好的是,让你的客户直接使用JDBC api,这实际上比使用实际上做得很少的execute方法简单得多。

如果您的代码库是Java 7,hacks to help you with that是确保清理JDBC资源的便捷方式。如果没有,你将不得不使用显式finally子句(调用close()最终嵌套在他们自己的try / catches中。)

至于您所看到的例外情况,他们的信息非常明确。您在关闭()编辑后使用ResultSet。问题是为什么。我没有一个简单的答案,但总的来说,你对资源清理并不是很干净;我怀疑这是问题所在。我很惊讶您设法使用此代码运行2000个查询,因为您正在泄漏Connections并且应该已经用完了。所以有一些谜团。但不管怎样,你偶尔会尝试使用ResultSets,因为它们已经被close()编辑,可能还有其他一些Thread。也许你正在做一些非显而易见的事情来关闭()连接,比如使用resultSet.getStatement(),getConnection()来找到你需要关闭的资源(),然后在你完成工作之前关闭()连接使用ResultSet?

祝你好运!