2

我有一个使用 Tomcat JDBC 连接池的服务器应用程序。

这是我用来创建数据源的代码:

PoolProperties connProperties = new PoolProperties();
connProperties.setUrl(resources.getProperty("db.url"));
connProperties.setDriverClassName(resources.getProperty("db.driver"));
connProperties.setUsername(resources.getProperty("db.user"));
connProperties.setPassword(resources.getProperty("db.password"));
connProperties.setJmxEnabled(true);
connProperties.setTestWhileIdle(false);
connProperties.setValidationQuery("SELECT 1");
connProperties.setTestOnReturn(false);
connProperties.setValidationInterval(30000);
connProperties.setTimeBetweenEvictionRunsMillis(30000);
connProperties.setMaxActive(500);
connProperties.setInitialSize(50);
connProperties.setMaxWait(10000);
connProperties.setRemoveAbandonedTimeout(60);
connProperties.setMinEvictableIdleTimeMillis(60000);
connProperties.setSuspectTimeout(60);
connProperties.setMaxIdle(50);
connProperties.setMinIdle(10);
connProperties.setLogAbandoned(false);
connProperties.setRemoveAbandoned(true);
connProperties.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");

dataSource = new DataSource();
dataSource.setPoolProperties(connProperties); 

然后我有一种从池中获取连接的方法

protected Connection getDbConnection() throws Exception
{
    dbConn = dataSource.getConnection();
    return dbConn;
}

每次我想执行一条语句时,我都会调用这段代码:

protected CallableStatement executeCSqlQuery(String sql) throws Exception
{
    CallableStatement cstmt;
    ResultSet rs = null;

    try {
        cstmt = getDbConnection().prepareCall(sql);     
        cstmt.execute();            
    } catch (SQLException e) {
        throw e;
    }

    return cstmt;
}

这是调用前面代码的示例:

try {
    cstmt = dbConnection.executeCSqlQuery(query);
    rs = cstmt.getResultSet();
} catch (Exception e) {
    // do smething
} finally {
    try {
        if (cstmt != null) {
            cstmt.close();
        }
        dbConnection.shutdown();
    } catch (Exception e) {
        // do something
    }
}

public void shutdown() {
    if (this.dbConn != null) 
        this.dbConn.close();
}

我面临的问题是,当我每隔 X 秒在线程中执行一次调用时,我会时不时地收到一个异常“语句已关闭”。我不确定为什么会这样。我认为这可能是驱动程序错误或与数据库的连接失败(在不同的服务器上运行)。

我没主意了。我错过了什么?

我应该改用c3p0连接池吗?

4

3 回答 3

4

我创建了赏金来帮助 Reznik,但我最终通过查看他的代码找出了问题所在。

问题是每次从池中获取新连接时

protected Connection getDbConnection() throws Exception
{
    dbConn = dataSource.getConnection();
    return dbConn;
}

对象dbConn更新为新连接。

例子:

T1调用getDbConnection()

T2调用getDbConnection()

T1执行查询、处理resultSet和调用shutdown()

public void shutdown() {
    if (this.dbConn != null) 
        this.dbConn.close();
}

因为T2更新了对象,正在使用的连接T2将被关闭T1

T2尝试使用连接,但它已经关闭。

这种方式,而不是总是更新连接,只需返回它,然后添加额外的逻辑来关闭从池中获取的连接。

于 2013-11-10T22:25:25.800 回答
2

我注意到两件事:

1)connProperties.setTestOnReturn(false); 应更改为 true。否则你的连接不一定有效。在您收到无效的声明之前,您可能不会收到通知。

2) 你应该总是关闭你的ResultSetStatementConnection对象。它确实涉及很多样板文件,或者您可以使用我的静态关闭实用程序方法

于 2013-11-09T21:51:37.957 回答
1

1)protected CallableStatement executeCSqlQuery(String sql) throws Exception返回可调用语句。如果您在方法内关闭它后再次尝试使用它,您可能会收到该错误。涉及该对象的所有处理都应在关闭它之前完成。

2)同样的方法有一个catch(SQLException ){throw e}。您要么想在那里处理异常,要么如果要传播它,请删除 try-catch

3) 我可以在最后一段代码中看到 以rs = cstmt.getResultSet();获取资源的相反顺序关闭资源始终是一个好习惯,正如您在为 Peter 链接的帖子中所读到的那样。所以rs.close(); cstmt.close(); connection.close();。它不包含在您的示例中,但如果您在关闭它后返回 ResultSet,您将遇到与 1) 中描述的相同的问题

于 2013-11-08T13:11:57.170 回答