【问题标题】:java.sql.SQLException: ResultSet closed on sqlitejava.sql.SQLException: ResultSet 在 sqlite 上关闭
【发布时间】:2017-04-16 06:29:56
【问题描述】:

我查看了很多答案,但遗憾的是没有人回答我的问题,我仍然无法弄清楚为什么我会收到 ResultSet closed

这是导致问题的try 代码 sn-p:

        System.out.println(" System Info! @CHKMD5Files(): Found pre-existing details: "+TOTAL);

        Statement stmMD5 = null;
        Connection connMD5 = null;
        ResultSet rs_MD5 = null;
        String RESULTMD5 = null;

        try {
            connMD5 = DriverManager.getConnection("jdbc:sqlite:" + bkpPATH+ hostname + ".db");
            stmMD5 = connMD5.createStatement();
            connMD5.setAutoCommit(false);

            while (ROWID <= TOTAL) {
                rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");
                RESULTMD5 = rs_MD5.getString("MD5");
                skipBuffer.write(RESULTMD5);
                skipBuffer.newLine();
                skipBuffer.flush();
                ROWID++;
                }
            System.out.println(" System Info! @CHKMD5Files(): Done with try");

        } catch (Exception ex) {
            System.out.println(" System Error! @CHKMD5Files (2): " + ex);
            System.exit(5);
        } finally {
            if (stmMD5 != null){
                stmMD5.close();
                System.out.println(" System Info! @CHKMD5Files (2): Closing Statement(stmMD5)");
            }
            if (connMD5 != null) {
                connMD5.close();
                System.out.println(" System Info! @CHKMD5Files (2): Closing Connection(connMD5)");
            }
            skipBuffer.close();
        }
    }

看起来 while 循环甚至没有运行,因为如果我将 print 语句放入循环中,则不会返回任何内容。

【问题讨论】:

  • 什么时候出现这个错误?
  • 你能添加错误的堆栈跟踪吗?会有很大帮助
  • "看起来 while 循环甚至没有运行,因为如果我将 print 语句放入循环中,则不会返回任何内容。"这意味着 ROWID 变量给你带来了问题。所以把它的代码。即在 ROWID 中存储结果的查询部分。
  • 这实际上取决于她将 print 语句放在哪里:如果她将 print 语句作为 while 循环内的最后一行,并且错误是由第一行(或任何其他行)引起的,那么它将正常打印不工作
  • @ManojShukla 但我怀疑这是错误,否则我认为她不会收到那个例外。我宁愿认为它与声明的execute有关

标签: java sqlite jdbc sqlexception


【解决方案1】:

当你想使用ResultSet时,你必须先调用next方法在结果的第一行设置ResultSet的指针。正如方法的Javadoc 所说:

ResultSet 游标最初位于第一行之前;第一次调用 next 方法使第一行成为当前行; ...

所以如果你不调用它,你就不会指向没有结果,getString 方法(在RESULTMD5 = rs_MD5.getString("MD5"); 中使用)将生成该异常。所以至少添加

rs_MD5.next()

在您提取结果之前。 next 方法返回一个布尔值来指示它是否可以到达下一行。因此,您可能希望在提取任何列值之前添加一个if-statement 来检查该值是否为真,因为如果next 未能到达下一行(并返回假),它会将指针设置为无效行(没有剩余),如果您尝试访问结果,您将得到相同的错误(请参阅上面next 的 javadoc 链接)。

但不幸的是即使你添加一个对next的调用,你也会在第二次迭代中得到同样的错误,因为你不能使用相同的Statement-object来执行不同的查询。 每个Statement-object 只能产生一个ResultSet
要解决这个问题,您至少应该替换

rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");

rs_MD5 = connMD5.createStatement().executeQuery(
        "SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';"
  );

但我会建议您否则,因为创建一个新的Statement-object 非常耗时(每个都必须在执行之前编译)。由于每次迭代中唯一改变的是ROWID,因此在每次迭代中重新编译相同的东西将是一种可怕的浪费时间。所以请改用PreparedStatement。它允许您使用只编译一次的语句,并且您可以通过在其中注入参数来重复使用多次(在编译之后)。 要使用PreparedStatement,您应该这样做:

Connection conn = ... //Connection to your database
PreparedStatement ps = conn.preparedStatement("SELECT * FROM person WHERE name = ? AND age = ?");

//First search all persons with name "J.Baoby" and age = 5
ps.setString(1, "J.Baoby");
ps.setInt(2, 5);
ResultSet set1 = ps.executeQuery();
// Do something with it 
// ....

//Now I need persons with name "Henry" and age = 25
ps.setString(1, "Henry");
ps.setInt(2, 25);
ResultSet set1 = ps.executeQuery();
// Do something with it
// ...

注入这些参数的方法是使用setXXX 方法,第一个参数是“?”的索引(从1 开始)您要替换,第二个参数是值。 XXX 替换为您要注入的值的类型。您可以注入的参数类型有限,因此在注入对象之前先检查Java API。 您可以在Java API 中找到有关PreparedStatement 的更多信息 或on this site(还有更多示例)。

最后我想补充一点,当你确定你会赢时,你应该关闭所有 (JDBC) 资源(ConnectionStatementResultSetPreparedStatement,...)不再需要它们了。您不释放的资源是您的 JVM 可能分配给其他东西的浪费资源。不关闭资源是一个坏习惯,可能会导致性能下降。

祝你好运!

【讨论】:

    【解决方案2】:

    非常感谢您的所有回复并为我指出正确的路径,我已经设法解决了这个问题,这是因为 ROWID 在开始时没有数据,这导致了我的问题。

    检查它是否为空的附加语句解决了我的问题:

                    while (ROWID <= TOTAL) {
                    rs_MD5 = stmMD5.executeQuery("SELECT md5 FROM details WHERE ROWID = '"+ROWID+"';");
                    if (!rs_MD5.next() ) {
                        System.out.println(" System Info! @CHKMD5Files(): No data in rowid: "+ROWID);
                        ROWID++;
                    } else {
                        RESULTMD5 = rs_MD5.getString("MD5");
                        skipBuffer.write(RESULTMD5);
                        skipBuffer.newLine();
                        skipBuffer.flush();
                        ROWID++;
                        rs_MD5.close();
                    }
                }
    

    【讨论】:

    • 这给了我一些我没有预见到的见解,谢谢
    猜你喜欢
    • 1970-01-01
    • 2011-06-19
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2013-04-26
    相关资源
    最近更新 更多