2016-12-01 91 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

這給了我一些見解,我沒有看到未來,謝謝 –

相關問題