java.sql.ResultSet absolute造成out of memory

java.sql.ResultSet 使用absolute方法可以移動ResultSet的指標到想要的筆數,

當 JDBC跟資料庫要資料時,會回傳一個ResultSet,但不是把所有查詢的結果均回傳至Web Server端,

而是只給前面幾筆資料,可以利用ResultSet的方法setFetchSize來設定一次回傳的筆數,

(一次傳的多,等待的時間就比較長,傳的太少,要一直跟資料庫要ResultSet.next()也會比較慢)

當ResultSet向下移動碰觸或是快要碰觸到目前回傳的筆數時,會自動再跟資料庫要設定好的筆數,

而把目前筆數以上的資料全都暫存在記憶體裡。

以上是ResulSet的基本原理,當一次查詢的量夠大時,而利用absolute來移動到想要的Row時,

就有可能發生out of memory的問題,

舉個列子:

當想要取得總筆數來做分頁的totrec計算,這時利用absolute移動到最後一筆,取得getRow()來當總數,

這時資料庫會把所有的資料均吐出來給Web Server,而Web Server也會把資料暫存到記憶體裡,

而有多人一起執行這個動作時,像jsp同時有多人一起看同一頁時,則記憶體會完全來不及釋放,

試想有十萬筆*n個要求的資料暫存在記憶體裡,所以這很容易行成out of memory的Runtime Error。

解決方法其實很簡單,就是不要用absolute來取得總筆數,而是利用SQL先跟資料庫要總筆數,

(select count(*) as totrec from table where 條件)

當總筆數大於零時,再跟資料庫查詢想要的資料範圍(Oracle:where field between a And b 或是MySQL: limit a,b),

二次的請求一定比直接使用absolute佔用的記憶體少。

相關資料:

Java Gossip: ResultSet 游標控制

Interface ResultSet

發表迴響