2009-09-09 61 views
1

我正在處理Spring JDBC DAO中的大量數據。當檢索操作發生在一個單獨的線程中(使用ExecutorService)時,DAO直接返回一個迭代器覆蓋對象上的對象,該對象使用有界的使用take()進行操作。在Spring中同時訪問JDBC ResultSet

在此線程中,我看到以下行爲:檢索工作正常,但某些對ResultSet的調用正在導致調用掛起。這些調用

  • isClosed()
  • isLast會()

但不

  • isAfterLast()
  • isBeforeFirst( )
  • isFirst()

很顯然,我需要知道的最後一個元素是什麼(爲了插入一個特殊元素成產生的迭代器hasNext(假阻塞隊列)方法) 。在將對象放入BlockingQueue之前,我可以通過查找ResultSet中的行數來解決這個問題,但這有點笨拙。有沒有線程安全的方式來使用ResultSets?

切換到多線程數據源(我測試過C3POs ComboPooledDataSource)似乎沒有幫助。

注:第一次(錯誤地)確定了我這個問題here

回答

1

正確的解決方案是設置適當的ResultSet類型。isLast()ResultSet的類型可以通過使用PreparedStatementCreator而不是SQL字符串來設置。 查詢()調用JdbcTemplate。這些實例通過PreparedStatementCreatorFactory獲取。在這樣的工廠中,可以設置類型ResultSet(例如「TYPE_SCROLL_INSENSITIVE」)。

+1

嗯,晦澀..... – skaffman 2009-10-01 11:43:22

1

我不認爲java.sql.ResultSet是線程安全的,但無可否認這實際上不是在Javadoc提及。如果調用來自不同線程的ResultSet方法導致這些方法調用掛起,我一點都不會感到驚訝。

作爲一種替代方案,我建議讓您的檢索線程成爲ResultSet的唯一用戶,關閉這些行,然後將數據本身轉儲到您的BlockingQueue。然後,檢測結果集的結尾並將您的EOF標記放在隊列中變得微不足道。

JDBC中用於迭代非常大的結果集的一般首選機制是使用java.sql.StatementfetchSize屬性,儘管這高度依賴於數據庫和JDBC驅動程序。我知道Oracle驅動程序會尊重這個設置,但不知道其他人。如果驅動程序決定在將第一行提交給內存之前需要將整個結果集提取到內存中,則無論您做什麼,都將無法在獲取下一行時處理第一行。

+0

我目前使用的是抓取大小。這是需要使用阻塞隊列的數據使用者的(相對)較低的處理速度。 AFAIK目前有問題的DAO是ResultSet的唯一用戶。通過明確的行計算解決方法,我可能會讓事情保持原樣並相應地記錄ResultSet行爲。 – yawn 2009-09-09 13:48:43

+0

是的,但DAO是從多個線程訪問的,所有這些線程都在相同的ResultSet上運行? – skaffman 2009-09-09 16:49:26

+0

不,ResultSet應該只能被一個線程訪問。我將不得不進一步調查。 – yawn 2009-09-10 07:14:22