我有一个程序向数据库发出多个请求,打开和关闭连接以执行它需要做的事情。对于每个连接,它执行一个返回50个结果和更新的选择;它每次连接大约做10次。之后,关闭连接,并采取新的连接。但是最近我们遇到了一些随机问题,其中出现了这个SQL异常:
java.sql.SQLException:您无法对已关闭的Statement !!!进行操作
此错误随机出现。它首先出现在执行中期,并且在我设法重现它的唯一时刻,它发生在程序的启动时(之后我再次启动它,没有做任何改变,它工作得非常好)。我已经查看了代码,但在使用它之前连接没有关闭(在预准备语句中插入参数时发生错误)。我已经使用c3p0来管理连接池了,所以我不知道还有什么地方可以看。
之前有人遇到过这个错误吗?关于在哪里寻找或如何重现它的任何建议,以便我可以正确测试它?
编辑:这是一段有问题的代码
try{
//send row to producer
producer.processItem(fields);
if (stmtLasProcessedTransaction == null) {
stmtLasProcessedTransaction = getDbConnection().prepareStatement("UPDATE JTICKET_SUBSCRIBER SET LAST_PROCESSED_ROW = ? WHERE NAME = ? ");
logger.trace("creating statement");
}
//update last processed transaction
logger.trace("Setting the primary key to the prepared statement");
stmtLasProcessedTransaction.setString(1, primaryKey);
logger.trace("Setting the name to the prepared statement");
stmtLasProcessedTransaction.setString(2, name);
logger.trace("Attempting to execute the update on JTICKET_SUBSCRIBER in consumer {}",this.name);
stmtLasProcessedTransaction.executeUpdate();
logger.trace("Commiting execution");
getDbConnection().commit();
logger.trace("Update on JTICKET_SUBSCRIBER in consumer {} executed successfully",this.name);
if (processedRows % 500 == 0) {
logger.trace("resetting prepared statement");
stmtLasProcessedTransaction.close();
logger.trace("statement closed");
stmtLasProcessedTransaction = null;
}
processedRows++;
}catch(SQLException sqlException){
logger.error("An SQL error ocurred while processing consumed item. Closing database connection and statement",sqlException);
try{
stmtLasProcessedTransaction.close();
logger.info("Previous prepared statement of db consumer {} closed",this.name);
}catch(Throwable throwable){
logger.info("Couldn't properly close the prepared statement of db consumer {}",this.name);
}finally{
stmtLasProcessedTransaction=null;
}
try{
databaseConnection.rollback();
logger.info("Rollback of db connection of consumer {} done successfully",this.name);
databaseConnection.close();
logger.info("Previous connection of db consumer {} closed",this.name);
}catch(Throwable throwable){
logger.info("Couldn't rollback and/or close the connection of db consumer {}",this.name);
}finally{
databaseConnection=null;
}
throw sqlException;
}catch(Exception exception){
logger.error("An error ocurred while processing consumed item.", exception);
throw exception;
}
预准备语句是一个局部变量,而不是函数一,所以它可以在每个循环中重复使用(这个函数是一个函数的一部分,对于查询中的每个结果都会调用一次语句到同一个数据库连接)。当我尝试处理准备好的语句时会发生错误。
最新的堆栈:
18/06/15 15:54:34.841 [ecbcbcmt] TRACE DatabaseConsumer - 创建声明18/06/15 15:54:34.850 [ecbcbcmt] ERROR DatabaseConsumer - An 处理消耗的项目时出错。值java.sql.SQLException: 你不能在一个封闭的声明中操作!在 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) 〜[mchange-commons-java-0.2.9.jar:0.2.9] at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77) 〜[mchange-commons-java-0.2.9.jar:0.2.9] at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:488) 〜[c3p0-0.9.5.jar:0.9.5] at us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.processRow(DatabaseConsumer.java:152) [bin /:na] at us.inswitch.jticket.subscriber.consumer.database.DatabaseNumberConsumer.processRows(DatabaseNumberConsumer.java:73) [bin /:na] at us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.start(DatabaseConsumer.java:65) [bin /:na] at us.inswitch.jticket.subscriber.consumer.Consumer.run(Consumer.java:35) [bin /:na] at java.lang.Thread.run(Thread.java:662)[na:1.6.0_38-ea] 引起:java.lang.NullPointerException:null at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:482) 〜[c3p0-0.9.5.jar:0.9.5] ...省略了5个共同框架18/06/15 15:54:34.852 [ecbcbcmt]警告DatabaseConsumer - 出现错误 同时消耗表数据。 DatabaseConsumer将重新启动。 java.sql.SQLException:您无法对已关闭的Statement进行操作!在 com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) 〜[mchange-commons-java-0.2.9.jar:0.2.9] at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77) 〜[mchange-commons-java-0.2.9.jar:0.2.9] at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:488) 〜[c3p0-0.9.5.jar:0.9.5] at us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.processRow(DatabaseConsumer.java:152) 〜[bin /:na] at us.inswitch.jticket.subscriber.consumer.database.DatabaseNumberConsumer.processRows(DatabaseNumberConsumer.java:73) 〜[bin /:na] at us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.start(DatabaseConsumer.java:65) 〜[bin /:na] at us.inswitch.jticket.subscriber.consumer.Consumer.run(Consumer.java:35) [bin /:na] at java.lang.Thread.run(Thread.java:662)[na:1.6.0_38-ea] 引起:java.lang.NullPointerException:null at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:482) 〜[c3p0-0.9.5.jar:0.9.5] ...省略了5个常见框架
它很奇怪,因为它完全是随机的。我们已经启动并运行了一段时间的程序,所有连接都运行良好,我们遇到了这种问题。
答案 0 :(得分:0)
使用局部变量,或者仔细使用PreparedStatements。 这样可以避免在Web应用程序中同时使用。
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
...
try (ResultSet rs = stmt.executeQuery()) {
...
} // rs close
} // Does stm.close()
当抛出异常时,try-with-resources也会关闭。
答案 1 :(得分:0)
语句stmtLasProcessedTransaction.close();出现在两个可疑的地方!!
1.在有条件的情况下尝试阻止
2.在拦截区内
更好的编程习惯是只有一个关闭语句,在finally块中也是如此
PS:你也可以在finally块中使用try-catch-finally