問題描述在通常的三層構架下客戶通過Browser請求Web服務器查詢數據庫而查詢結果是上千條甚至是上百萬條記錄要求查詢結果傳送到客戶端浏覽器並分頁顯示
考慮因素
Web服務器的資源消耗包括內存(用來存儲查詢結果)數據庫相關資源(數據庫連接對象ResultSet對象等等)
DB服務器資源的消耗包括游標會話等等
網絡開銷包括與數據庫建立會話傳輸查詢結果等等
JDBC中的幾個重要Class:
A ResultSet object maintains a cursor pointing to its current row of data Initially the cursor is positioned before the first row The next method moves the cursor to the next row and because it returns false when there are no more rows in the ResultSet object it can be used in a while loop to iterate through the result set
ResultSet是直接在數據庫上建立游標然後通過ResultSet的行位置定位接口來獲得指定行位置的記錄當用戶通過get方法獲取具體紀錄的內容時ResultSet才從數據庫把所需數據讀到客戶端
Oracle的ResultSet實現似乎會在本地緩存用戶讀取過的數據導致內存消耗會隨讀取數據的增加而增加這樣如果一次查詢並讀取海量數據即使讀出數據後馬上丟棄(比如直接寫入文件)內存消耗也會隨查詢結果的增加而遞增
The RowSet interface extends the standard javasqlResultSet interface A RowSet object may make a connection with a data source and maintain that connection throughout its life cycle in which case it is called a connected rowset A rowset may also make a connection with a data source get data from it and then close the connection Such a rowset is called a disconnected rowset A disconnected rowset may make changes to its data while it is disconnected and then send the changes back to the original source of the data but it must reestablish a connection to do so
RowSet是JDBC中提供的接口Oracle對該接口有相應實現其中很有用的是 oraclejdbcrowsetOracleCachedRowSet OracleCachedRowSet實現了ResultSet中的所有方法但與ResultSet不同的是OracleCachedRowSet中的數據在Connection關閉後仍然有效
解決方案一直接使用ResultSet來處理
從ResultSet中將查詢結果讀入collection緩存在HttpSession或有狀態bean中翻頁的時候從緩存中取出一頁數據顯示這種方法有兩個主要的缺點一是用戶可能看到的是過期數據二是如果數據量非常大時第一次查詢遍歷結果集會耗費很長時間並且緩存的數據也會占用大量內存效率明顯下降
對上述方法的一種改進是當用戶第一請求數據查詢時就執行SQL語句查詢獲得的ResultSet對象及其要使用的連接對象都保存到其對應的會話對象中以後的分頁查詢都通過第一次執行SQL獲得的ResultSet對象定位取得指定頁的記錄(使用rslast();rsgetRow()獲得總計錄條數使用rsabsolute()定位到本頁起始記錄)最後在用戶不再進行分頁查詢時或會話關閉時釋放數據庫連接和ResultSet對象等數據庫訪問資源每次翻頁都只從ResultSet中取出一頁數據這種方式在某些數據庫(如oracle)的JDBC實現中差不多也是回緩存所有記錄而占用大量內存同時速度也非常慢
在用例分頁查詢的整個會話期間一個用戶的分頁查詢就要占用一個數據庫連接對象和結果集的游標這種方式對數據庫的訪問資源占用比較大並且其利用率不是很高
優點減少了數據庫連接對象的多次分配獲取減少了對數據庫的SQL查詢執行
缺點占用數據庫訪問資源-數據庫連接對象並占用了數據庫上的資源-游標會消耗大量內存
解決方案二定位行集SQL查詢
使用數據庫產品提供的對查詢的結果集可定位行范圍的SQL接口技術在用戶的分頁面查詢請求中每次可取得查詢請求的行范圍的參數然後使用這些參數生產取得指定行范圍的的SQL查詢語句然後每次請求獲得一個數據庫連接對象並執行SQL查詢把查詢的結果返回給用戶最後釋放說有的數據庫訪問資源
這種方式需要每次請求時都要執行數據庫的SQL查詢語句對數據庫的訪問資源是使用完就立即釋放不白白占用數據庫訪問資源 對特定(提供了對查詢結果集可定位功能的)的數據庫產品如Oracle(rowid或rownum )DB(rowid或rownum ()) PostgreSQL(LIMIT 和 OFFSET)mySQL(Limit)等(MS SQL Server 沒有提供此技術)
下面是在oracle下的查詢語句示例
SELECT * FROM ( SELECT row_* rownum rownum_ FROM ( ) row_ WHERE rownum <= {pageNumber*rowsPerPage}) WHERE rownum_ > {(pageNumber)*rowsPerPage}
優點對數據庫的訪問資源(數據庫連接對象數據庫游標等)沒有浪費這些資源的充分重復的利用
缺點對每次分頁面查詢請求要頻繁的從Web容器中獲得數據庫訪問資源(數據庫連接對象和數據庫游標)並建立連接要依賴於具體的數據庫產品的支持
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25890.html