2013-12-13 43 views
0

代碼:RuntimeException - Exhausted Resultset - 它怎麼會發生?

// Start the query. 
    final ResultSet r = prepared.executeQuery(); 
    try { 
     // Returning false from oneRow will stop the process. 
     boolean goOn = true; 
     while (r.next() && goOn) { 
     log.trace("Result: {}", toString(r)); 
     // We did do at least one. 
     ran = true; 
     goOn = oneRow(r); 
     } 
    } finally { 
     try { 
     // Always remember to close the ResultSet. 
     r.close(); 
     } catch (SQLException ex) { 
     log.error("Close failed", ex); 
     } 
    } 

    // Handle one row. 
    public boolean oneRow(ResultSet r) throws Exception { 
     String xml1 = r.getString(1); 
     String xml2 = r.getString(2); 
     if (xml1 == null && xml2 == null) { 
     // Probably compressed. 
     xml1 = decompress(r, 3); 
     xml2 = decompress(r, 4); 
     } 
     return false; 
    } 

    private static String decompress(ResultSet rs, int col) throws SQLException { 
    // Exception gets thrown here!!! ??? 
    final InputStream compressed = rs.getBinaryStream(col); 
    ... 

正如你可以看到這是不是不叫ResultSet.next()的明顯的問題。不僅如此,我還在ResultSet中撥打了getString兩次,這是第三次打破它。

請注意,這是一個偶然的問題,這段代碼大部分時間都正常工作。

查詢看起來像:

"SELECT P1.XML XML1, " 
     + "P2.XML XML2, " 
     + "P1.CompressedXML CompressedXML1, " 
     + "P2.CompressedXML CompressedXML2 " 
     + "FROM Table1 P1 " 
     + "LEFT JOIN Table2 T2 ON T2.ID = P1.ID " 
     + "LEFT JOIN Table1 P2 ON P2.ID = T2.Item_Code " 
     + "WHERE P1.ID = ?" 

我意識到這是一個相當亂倫的查詢,但正如我所說 - 這一切工作正常的大部分時間。

新增

通過張貼user1933888答案促使它發生,我認爲,因爲我使用的是自家種的連接池有可能是一個準備好的聲明與自身之間的兩個線程共享不同的干擾連接?

我相信,同一連接永遠不會被兩個線程同時使用,但預備語句可以共享,因爲它應該駐留在數據庫中。

+0

這可能是一些數據問題 –

+0

你可以顯示堆棧跟蹤嗎? – beny23

+0

還要注意,oneRow總是返回false,所以你永遠不會處理多於一行的數據。 – beny23

回答

1

當你的PreparedStatement鏈接到一個連接時,如果你在線程之間共享PreparedStatement,你最終會共享一個連接,這肯定會導致問題。

確實,語句通常緩存在數據庫中以避免重新解析它,但每個線程仍需要一個PreparedStatement對象,以避免數據庫驅動程序混淆線程想要的內容。

一般來說,我會避免使用家庭連接池,因爲一般情況下,AppServers會爲您或者(如果您不在AppServer中)爲您提供連接池庫,那麼爲什麼要重新創建連接池庫輪。

一般:

  • 可以併發線程之間共享數據源
  • 你不應該共享連接,PreparedStatement的或併發線程

連接池將確保非之間的ResultSet對象併發線程可以重用連接並且JDBC驅動程序將內部緩存語句

希望m有意義。

+0

我確定我在另一個網站(可能是JavaLobby,但現在找不到它)上發現了一篇文章,它暗示準備好的語句存儲在DBMS中,因此一旦它們被創建就可以從任何線程/連接訪問 - 實際上它們會持續作爲某種形式的計劃。我很樂意爲此糾正。 – OldCurmudgeon

+0

+1 - 我同意自制連接池 - 這是繼承代碼,我正在將其切換到適當的池中。 – OldCurmudgeon

+0

... *也許JavaLobby * ...它當然是[JavaRanch](http://www.javaranch.com/),但我仍然無法找到參考。 – OldCurmudgeon