如果底层连接已关闭,为什么isClosed()方法对Prepared Statements不返回true?

时间:2014-04-09 19:02:12

标签: java sql jdbc

正如标题所说,我想知道为什么准备好的语句.isClosed()方法在关闭底层流后会返回false(使用JDBC)。

public void someTest() throws SQLException, InterruptedException {
    Connection conn = DBHelper.newConnection();
    PreparedStatement statement = conn.prepareCall(CLEANUP_DELETE);

    conn.close();

    System.out.println(statement.isClosed());

    Thread.sleep(1000);
    System.out.println(statement.isClosed());
}

输出

false
false

但是如果你试图调用set方法或执行,你会得到这个:

java.sql.SQLException: org.apache.commons.dbcp.DelegatingCallableStatement with address: "SQLServerCallableStatement:32" is closed.
at org.apache.commons.dbcp.DelegatingStatement.checkOpen(DelegatingStatement.java:137)
at org.apache.commons.dbcp.DelegatingPreparedStatement.setInt(DelegatingPreparedStatement.java:120)
at org.apache.commons.dbcp.DelegatingPreparedStatement.setInt(DelegatingPreparedStatement.java:120)
at com.ipti.ptl.common.messagetable.MessageHandlerTest.someTest(MessageHandlerTest.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606) .....

1 个答案:

答案 0 :(得分:1)

这可能是DBCP库的一个错误,尽管我必须查看JDBC规范。您是否尝试过为驱动程序使用本机JDBC PreparedStatement

修改

查看MySQL连接器源代码(可用here),看起来Connection.close()的实现实际上关闭了与连接关联的所有语句。因此,当使用MySQL JDBC驱动程序时,如果连接已关闭,PreparedStatement.isClosed() 返回true。我不太确定JDBC规范对此有何看法。

在您的情况下,我不确定DBCP库是否将对isClosed()的调用委托给底层驱动程序,这就是为什么我建议删除这个额外的层并看看会发生什么。如果DBCP中有错误,我会报告。如果您使用的底层驱动程序中存在错误,我也会报告。假设这确实是一个错误。

编辑2

根据评论,JDBC 4.1规范说(第9.4.4.1节):

  

的Connection.close

     

应用程序调用Connection.close()方法来指示它有   使用连接完成。从给定创建的所有Statement对象   Connection的close方法将关闭Connection对象   对象被称为。

所以我希望这个陈述确实是封闭的。因此,DBCP库或正在使用的MS SQL Server驱动程序中存在错误。