2016-12-01 105 views
0

我看了很多答案,但不幸的是没有回答我的问题,我仍然无法弄清楚为什么我得到ResultSet closedjava.sql.SQLException:结果集关闭sqlite

这里是try代码片段that`s导致了问题:

 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循环甚至不运行,因为如果我把打印语句在循环返回任何内容。

+0

在什么时候,你得到这个错误? –

+0

你可以添加错误的堆栈跟踪?这会有很大的帮助 –

+1

“看起来while循环甚至没有运行,因为如果我把循环印出的东西没有返回。”这意味着ROWID变量会给你带来问题。所以把它的代码。即将结果存储在ROWID中的查询部分。 –

回答

2

当您想要使用ResultSet时,您必须首先调用next方法,以在结果的第一行上设置ResultSet的指针。正如该方法的Javadoc所述:

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

所以,如果你不叫,你没有指向任何结果和getString方法(在RESULTMD5 = rs_MD5.getString("MD5");使用)会产生异常。因此,在提取结果之前至少要添加

rs_MD5.next() 

next方法返回一个布尔值来指示它是否可以到达下一行。因此,如果next未能到达下一行(并返回false),那么您可能需要添加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 APIon this site(有更多的例子)中找到更多关于PreparedStatement的信息。

截至去年,我想补充一点,你应该关闭所有(JDBC)ressources(ConnectionStatementResultSetPreparedStatement,...)当你确定你将不再需要它们了。您不释放的资源会浪费您的JVM可能分配给其他资源的资源。不关闭你的资源是一个坏习惯,并可能导致性能损失。

祝你好运!

1

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

附加声明检查,如果它是空的resulved我的问题:

   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(); 
       } 
      } 
+0

这给了我一些见解,我没有看到未来,谢谢 –

相关问题