Tomcat JDBC连接池问题:“语句已关闭”

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

这是我用来创建DataSource的代码:

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秒在线程中执行一次调用时,我偶尔会遇到exception“语句已关闭”。 我不确定为什么会这样。 我认为它可能是驱动程序错误或与数据库连接失败的东西(在不同的服务器上运行)。

我没有想法。 我错过了什么?

我应该使用c3p0连接池吗?

我创造了赏金以帮助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尝试使用连接,但它已经关闭。

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

我注意到两件事:

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

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

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

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

3)我可以在最后一段代码中看到rs = cstmt.getResultSet(); 按照他们获得的相反顺序关闭资源总是一个好习惯,正如您在为Peter链接的post中所读到的那样。 所以rs.close(); cstmt.close(); connection.close(); rs.close(); cstmt.close(); connection.close(); 。 它没有包含在您的示例中,但如果您在关闭后返回ResultSet,则会遇到1)中描述的相同问题