Jive筆記4--結果集分頁處理 (轉)
by Shyguy
2002/09/18
轉載請標明作者和出處
在應用中,難免和打交道,對於返回的結果集,究竟該如何處理?
尤其是,當你的一個查詢可能會返回數萬條紀錄的時候,你還能像某些騙錢騙精力的垃圾書本上介紹的用rs.next()來處理麼?
呵呵,我以前就是這麼幹的,直接傳回resultset,在jsp中while(rs.next())迴圈中一個
一個的處理。
還有,返回結果的分頁處理的問題。很多時候我們的Web應用(或者其他)都是針對某一種資料庫的(感覺商業應用絕大多數是,業餘的多是my,還敢用jc連線sqlServer的,估計是被M$養廢了)。所以我常常會針對某些資料庫的特性寫一些專門的SQL語句或者過程來確定返回結果集的大小,以實現分頁處理(其實偶是資料庫白痴,除了/insert/update,其他的不知道!)。我以前就是用偽列來實現在Oracle上處理記錄結果集的分頁的。
慢慢的,為了所謂的降低程式碼耦合度,我對查詢結果集的程式碼進行了重構,於是稍微進步了一點,在某個queryManager之類的類中傳出一個Enumeration,裡邊的每個對應了資料庫中的一條紀錄。嘿嘿,居然也能湊合著對付500多人使用了。
可是,這也不是最好的辦法,畢竟,如果真的返回了幾萬條紀錄,這樣的處理方法不但佔,而且也不搞。
記得以前在bqlr.com中看到一篇關於“查詢結果返回rs,還是集合”的討論,答案是用Iterator。
可是裡邊的程式碼很籠統,對於從未用過iterator的人來說,基本上沒有什麼可以模仿和參照的。
還好,我們有現成的,那就是Jive。
看看Jive中是怎麼實現的。
(A)我們以forum.jsp這個頁面為例,預設的,每頁顯示15條thread,可以指定從第n條開始顯示到n+page_size條。
程式碼如下:
ResultFilter filter = new ResultFilter(); filter.setStartIndex(start); //從第start條thread開始 filter.setNumResults(range); //頁面大小 // Set the moderation level minimum filter.setModerationRangeMin(forum.getModerationMinThreadValue()); // More forum properties int numThreads = forum.getThreadCount(filter); int numMessages = forum.getMessageCount(filter); // Iterator of threads ForumThreadIterator threads = forum.threads(filter); //返回thread Iterator,
透過分析上面程式碼,明確了需要重點分析ResultFilter,DBForum和ForumThreadIterator這三個類。
(B)看看ResultFilter.
這個類其實就是專門儲存查詢條件的,例如,可以查詢某天之前,由某人釋出的貼子等。一次查詢操作的所有查詢條件都儲存在這個類裡邊。
裡邊有一個比較有意思:public void setSortPropertyName(String sortPropertyName),嘿嘿可以把“是否具備某個property”作為查詢條件。我本來就想給jive新增thread置頂功能,看起來只要給需要置頂的thread加一個topMost屬性,然後改動skin就可以了。可謂是得來全不費工夫啊。
把查詢條件填充完畢以後,就可以把resultFilter傳給forum.threads()取結果了。
(C)看DBForum.threads()
public ForumThreadIterator threads(ResultFilter resultFilter) { //根據傳入的resultFilter構造一個查詢SQL語句(*注1) String query = getThreadListSQL(resultFilter, false); //返回一個確定返回的id列表,這裡預設大小是400個,例如,我要看1~15條紀錄 // threadBlock的length是400,從1~400(*注2) long [] threadBlock = getBlock(query.toString(), resultFilter.getStartIndex()); int startIndex = resultFilter.getStartIndex(); int endIndex; // If number of results is set to inifinite, set endIndex to the total // number of threads in the forum. if (resultFilter.getNumResults() == ResultFilter.NULL_INT) { endIndex = (int)getThreadCount(resultFilter); } else { endIndex = resultFilter.getNumResults() + startIndex; } //嘿嘿,理解了上面幾句程式碼先,然後來看這個iterator return new ForumThreadBlockIterator(threadBlock, query.toString(), startIndex, endIndex, this.id, factory); }
OK,關於(注1)
我分析了getThreadListSQL,這裡是構造了一個SQL查詢語句,這個語句前面的一些內容是:
SELECT jiveThread.threadID FROM jiveThread,xxxxx
那些xxxxx無非是一些查詢條件,是根據resultFilter中的查詢條件而自動生成的。
原來,如果了這個SQL的作用只能取回滿足條件的thread的ID號。
(注2)getBlock()
我對這裡的Block的理解是:指滿足查詢條件的查詢結果經過排序以後的序號集合,和資料庫中的threadID是不一樣的。
這裡的starIndex就是陣列,也就是那個Block的下標,而裡邊的內容(Long ),是真正的threadID
程式碼裡邊對於每Block陣列的大小,是固定的400。
舉例來說:
如果一次查詢返回1000條紀錄,我要從第510條開始(startIndex=510),那麼就是取第二塊block(blockID=1),塊起始位置(blockStart)是
500。
int blockID = startIndex / BLOCK_SIZE; int blockStart = blockID * BLOCK_SIZE;
如果你還有耐性看到這裡,並且接著讀jive程式碼的話,會發現,加下來無非就是從Cache中取該Block陣列,如果沒有找到,則老老實實的從資料庫中取出來,老老實實的放到陣列裡邊,放到Cache,最後扔出這個陣列。
這裡的資料庫處理程式碼比較普通
con = ConnectionManager.getConnection(); stmt = ConnectionManager.createScrollableStatement(con); // Set the maximum number of rows to end at the end of this block. ConnectionManager.setMaxRows(stmt, BLOCK_SIZE * (blockID+1)); ResultSet rs = stmt.executeQuery(query); // Grab BLOCK_SIZE rows at a time. ConnectionManager.setFetchSize(rs, BLOCK_SIZE); //一次最多取BLOCK_SIZE條,也就是400條 // Position the cursor right before the first row that we're insterested in. ConnectionManager.scrollResultSet(rs, blockStart);// 滾動遊標到blockStart // Keep reading results until the result set is exhausted or // we come to the end of the block. int count = 0; while (rs.next() && count < BLOCK_SIZE) { objectList.add(rs.getLong(1)); count++; }
看到這裡,我忽然領悟到,這裡的程式碼也只是複製而已,可是比我以前的複製到enumeration中要高階了好多。
首先,這裡限制了返回結果集的大小。
其次,複製的內容只是一個“指標”(嘿嘿,我喜歡用這個詞語)。
這樣就比較好的解決了上面的速度慢和浪費記憶體的問題。
(C)嘿嘿,接下來的事情相對就很簡單了。
1.根據startIndex計算出在該Block中的相對位置,也就是這個BlockArray中的下標啦,然後取得內容,也就是真正的threadID啦。
2.到threadCache中去取該threadObject,如果找不到,則老老實實的new thread(threadID),從資料庫中去取了。
這一切都是透過ForumThreadIterator中的hasNext()/next()/getElement()來實現的。大家自己去看一下就很容易搞清楚啦。
OK ok,休息一下休息一下。
歡迎大家提意見。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-958256/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Jive中的分頁處理 (轉)
- Laravel 手動建立分頁返回物件結果集Laravel物件
- Jive筆記7 -- Jive的硬傷 (轉)筆記
- go 如何處理資料庫返回的多結果集Go資料庫
- 學習Jive(Jdon版)分頁處理遇到了一些困惑,請指教
- Jdbc引入連線池,JdbcTemplate處理結果集的優化JDBC優化
- (反射+內省機制的運用)處理jdbc的結果集反射JDBC
- Jive筆記3----Jive2.1.1 License保護原理分析 (轉)筆記
- HarmonyOS NEXT 學習筆記4--雙向繫結$$筆記
- Mybatis底層原理學習(三):查詢結果集的處理原理MyBatis
- JAVA資料庫處理(連線,資料查詢,結果集返回)Java資料庫
- 資料採集,微軟控制元件分頁問題的處理微軟控制元件
- PLSQL Language Referenc-PL/SQL靜態SQL-查詢結果集處理SQL
- Jive筆記8--查詢的Bug (轉)筆記
- CSS 小結筆記之文字溢位處理CSS筆記
- iOS FMDB有返回結果集和無返回結果集iOS
- 處理JS分頁載入的網頁_recvJS網頁
- Spring專案處理分頁(邏輯和物理分頁)Spring
- Jive筆記2----關於Jive2中的中文搜尋 (轉)筆記
- 巧用臨時表將大結果集轉換為小結果集驅動查詢薦
- Oracle 儲存過程返回結果集|轉|Oracle儲存過程
- Oracle 儲存過程返回結果集 (轉)Oracle儲存過程
- Jive筆記6 --Database Package下面的暗黑世界 (轉)筆記DatabasePackage
- thinkPHP 分頁後如何處理資料PHP
- 封裝springmvc處理ajax請求結果封裝SpringMVC
- unity中取樣深度圖的結果處理Unity
- .NET 結果與錯誤處理利器 FluentResults
- 如何分頁顯示資料庫查詢結果?資料庫
- Java中文處理學習筆記——Hello Unicode (轉)Java筆記Unicode
- MySQL 儲存過程空結果集錯誤Error 1329 No data 的異常處理MySql儲存過程Error
- 關於 groupBy 分組查詢的分頁處理
- MySQL高效分頁解決方案集(轉)MySql
- 主頁的藝術處理 (轉)
- java異常處理筆記Java筆記
- Laravel 專案 偽靜態分頁處理Laravel
- 處理分頁的result型別問題型別
- DRF 過濾排序分頁異常處理排序
- 大量資料如何做分頁處理