【问题标题】:java.sql.SQLException: Invalid state, the CallableStatement object is closedjava.sql.SQLException: 无效状态,CallableStatement 对象已关闭
【发布时间】:2012-12-06 08:47:53
【问题描述】:

下面的代码会产生这个异常:

java.sql.SQLException: Invalid state, the CallableStatement object is closed.
    at net.sourceforge.jtds.jdbc.JtdsCallableStatement.checkOpen(JtdsCallableStatement.java:120)
    at net.sourceforge.jtds.jdbc.JtdsStatement.getConnection(JtdsStatement.java:1207)
    at net.sourceforge.jtds.jdbc.JtdsResultSet.getConnection(JtdsResultSet.java:409)
    at net.sourceforge.jtds.jdbc.JtdsResultSet.close(JtdsResultSet.java:470)
    at org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.close(DelegatingResultSet.java:152)
    at 

下面的这段代码有时会产生上面的错误,但有时不会:

   private void doRequest(HttpServletRequest request) throws IOException, ServletException {
        CallableStatement stmt = null;
        ResultSet rs = null;
        String someString;
        try {
            this.connectDB();
            stmt = this.conn.prepareCall("{call sp_SomeSP1(?)}");
            stmt.setLong(1, someFunc());

            rs = stmt.executeQuery();

            while (rs.next()) {
                if (rs.getInt(1)==someOtherFunc()) {
                    someString = rs.getString(2);
                    break;
                }
            }

            stmt = conn.prepareCall("{call sp_someSP(?, ?)}");
            stmt.setLong(1, someFunc());
            stmt.setTimestamp(2, new Timestamp(getFrom().getTime()));

            rs = stmt.executeQuery();
            if (rs.next()) {
                lastUpdated = rs.getTimestamp("LastUpdated");
            }

            request.setAttribute("lastUpdated", lastUpdated);

            LOGGER.debug("Forwarding to view...");
            getServletContext().getRequestDispatcher("/SomeJSP.jsp").forward(this.request, this.response);

        } catch (NamingException e) {
            LOGGER.error("Database connection lookup failed", e);
            sendError("Server Error");
        } catch (SQLException e) {
            LOGGER.error("Query failed", e);
            sendError("Server Error");
        } catch (IllegalStateException e) {
            LOGGER.error("View failed", e);
        } finally {
            try {
                if (rs!=null) rs.close(); 
            } catch (NullPointerException e) {
                LOGGER.error("Result set closing failed", e);
            } catch (SQLException e) {
                LOGGER.error("Result set closing failed", e);
            }
            try {
                if (stmt!=null) stmt.close();
            } catch (NullPointerException e) {
                LOGGER.error("Statement closing failed", e);
            } catch (SQLException e) {
                LOGGER.error("Statement closing failed", e);
            }
            try {
                this.closeDB();
            } catch (NullPointerException e) {
                LOGGER.error("Database connection closing failed", e);
            } catch (SQLException e) {
                LOGGER.error("Database connection closing failed", e);
            }
        }

这意味着doRequest()大部分时间都能正常工作,但有时我们会得到HTTP错误500,如果我们检查tomcat日志,我们会看到:

java.sql.SQLException: Invalid state, the CallableStatement object is closed.

【问题讨论】:

  • 验证参数index
  • 咦,你为什么要抓 NPE?
  • 你没有关闭你在这个例程中得到的第一个语句和结果集。
  • 语句 close 应该关闭结果集,并且在关闭的结果集上调用 close 应该是无操作(参见 javadoc);在我看来,这就像 JTDS 中的一个错误。

标签: java sql servlets jdbc


【解决方案1】:

您似乎在使用带有 Servlet 的成员变量(conn 变量)。但是,Servlet 通常可以由多个线程同时调用。你如何确保多个线程不会意外使用/关闭同一个连接?

【讨论】:

    【解决方案2】:
    stmt.setLong(1, someFunc());
    stmt.setTimestamp(3, new Timestamp(getFrom().getTime()));
    

    会的

    stmt.setLong(1, someFunc());
    stmt.setTimestamp(2, new Timestamp(getFrom().getTime()));
    

    【讨论】:

      【解决方案3】:

      在堆栈跟踪中看到此错误消息org.apache.tomcat.dbcp.dbcp.DelegatingResultSet.close,看起来您在关闭结果集时遇到错误

      我建议您更改结果集检查条件以在关闭结果集之前检查结果集是否仍然打开:

          if (rs!=null && ! rs.isClosed()){
              //resultset is there and not in closed state
              rs.close(); 
          }
      

      【讨论】:

      • 这听起来像是最好的分析或修复,但问题是为什么有时我们在访问网络应用程序时不会收到此错误?
      • 刷新一段时间后,它会抛出错误,你能解释一下那个场景
      • @xybrek 我怀疑结果集被不同的处理线程关闭的一些并发问题。尝试在准备调用方法中使用并发属性:stmt = con.prepareCall("{call sp_someSP(?, ?)}", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
      猜你喜欢
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      • 2013-04-26
      • 1970-01-01
      • 2015-11-03
      相关资源
      最近更新 更多