我有一个使用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秒就会在线程中执行一次调用时遇到异常“语句已关闭”。 我不确定为什么会这样。我认为它可能是驱动程序错误或与数据库连接失败的东西(在不同的服务器上运行)。
我没有想法。我错过了什么?
我应该使用 c3p0 连接池吗?
答案 0 :(得分:3)
我创造了帮助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 :(得分:2)
我注意到两件事:
1)connProperties.setTestOnReturn(false);
应改为true。否则您的连接不一定有效。在收到无效声明之前,您可能不会收到通知。
2)您应始终关闭 ResultSet , Statement 和 Connection 对象。它确实涉及很多样板,或者你可以使用我的static Close utility method。
答案 2 :(得分: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)中描述的相同的问题。