【问题标题】:Connection pooling in java using c3p0java中使用c3p0的连接池
【发布时间】:2013-12-21 05:59:28
【问题描述】:

我想在我编写的非 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 个查询,之后它停止工作,出现一些与资源分配相关的异常!

【问题讨论】:

标签: java connection-pooling c3p0


【解决方案1】:

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

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

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

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

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


所以,大问题。

首先是一些零碎的东西:System.exit(0) 是响应异常的不好方法。您的方法接受一个没有功能的dbName 参数。

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

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

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

如果您的代码库是 Java 7,try-with-resources 是确保清理 JDBC 资源的便捷方式。如果没有,您将不得不使用显式 finally 子句(对 close() 内部的调用 finally 嵌套在它们自己的 try/catch 中)。

至于您看到的异常,他们的消息非常清楚原因。在它们被 close()ed 之后,您正在使用 ResultSets。问题是为什么。我没有一个简单的答案,但总的来说,你对资源清理不是很干净;我怀疑这是问题所在。我很惊讶您设法使用此代码运行 2000 个查询,因为您正在泄漏连接并且应该已经用完了。所以有一些谜团。但是一种或另一种方式,您偶尔会尝试在它们被关闭()之后使用结果集,可能是由其他线程。也许你正在做一些不明显的事情来关闭()连接,比如使用 resultSet.getStatement(),getConnection()来找到你需要关闭()的资源,然后在你完成工作之前关闭()连接使用 ResultSet?

祝你好运!

【讨论】:

  • 我对问题进行了一些更改,请您看一下吗?
  • 您问题中的代码仍然没有关闭连接或语句。正如 Steve 所说,始终关闭 finally 块中的任何资源(或使用 Java 7 try-with-resources)。
  • 在我写作的时候,纪尧姆把重点说了一遍,比我还清晰简洁!
  • 如何在运行每个查询后关闭连接并仍然运行另一个查询?!一旦我关闭连接查询运行就会停止!
  • 在单个工作单元中运行和处理您需要执行的所有查询,然后关闭所有 JDBC 资源,包括连接。这里的“工作单元”不一定是事务,而是需要无条件地代表客户完成且无需等待的一系列操作。一旦您不能再做任何工作(例如,您正在等待客户端响应),请关闭()所有资源。当客户回来时重新打开它们。
猜你喜欢
  • 2010-11-30
  • 1970-01-01
  • 2013-08-20
  • 2019-12-31
  • 1970-01-01
  • 2014-12-22
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多