分頁問題是一個非常普遍的問題,開發者幾乎都會遇到,這裡不討論具體如何分頁,說明Web方式下分頁的原理。首先是查詢獲得一個結果集(表現為查詢資料庫所獲得的結果),如果結果比較多我們一般都不會一下顯示所有的數據,那麼就會用分頁的方式來顯示某些數據(比如20條)。因為Http的無狀態性,每一次提交都是當作一個新的請求來處理,即使是換頁,上一次的結果對下一次是沒有影響的。
這裡總結三種實現分頁的方式,不知道還有沒有別的!
1.每次取查詢結果的所有數據,然後根據頁碼顯示指定的紀錄。
2.根據頁面只取一頁數據,然後顯示這一頁,這裡要建構sql語句。
3.取一定頁數的數據,就是前面兩種的折法中。
這裡還要注意的是這些資料是放在request還是session中,這裡一一討論
1.一般不會放在session中,因為會佔用大量內存,所以要放在request裡面。
優點:實作比較簡單,查詢速度比較快。
缺點:佔用記憶體多一些,網路傳輸資料多。
對於資料量比較少的查詢這種方法比較適合。這裡有人把資料放在session中,這樣換頁的時候就不用重新查詢,但是這樣是極度不好的,強烈建議不要這樣使用。
2.肯定不會放在session中,因為放在session中沒有意義。
優點:佔用記憶體少。
缺點:比較麻煩,必須先獲得查詢結果的總數,因為要知道有多少紀錄才知道有多少頁。另外要建構分頁查詢語句,對於不同的資料庫是不一樣的。
3.這種情況是肯定放在session中了,要不然我幹嗎取好幾頁呀,這樣的實現是為了減少數據庫查詢的次數,比如我保存第1到10的紀錄,那麼換頁的時候如果在1到10之間就可以直接從session取得。如果換到11頁,我可以重新設定快取11到
20頁的資料(或5到15頁的資料),這樣的話換10次才需要一次資料庫查詢操作。
優點:佔用記憶體相對不多,提高平均查詢速度。
缺點:實作更加複雜,可能存在髒數據,需要自己定義一個快取集合。如果查詢的資料量比較大,可以考慮採用這樣。
下面的設計每次只獲取一頁數據,每次都要重新設定查詢總數,具體如何獲得自己實現,這是一個比較通用的分頁實現。
這裡設計一個介面:
package treeroot.util;import java.util.List;/*** 這個介面用來實作分頁功能,注意這裡沒有提供修改的功能。 * @author treerot* @version 1.0* @since 2004-9-30*/public interface Pageable{ /** * 取得資料結果* @return */ public List getResult(); /** * 取得查詢總數* @return */ public int getCount(); /** * 取得每頁紀錄數* @return */ public int getPageSize(); /** * 取得目前頁編號* @return */ public int getCurrentPage(); /** * 取得總頁數* @return */ public int getPages(); /** * 每頁預設顯示紀錄數*/ public final static int DEFAULT_PAGESIZE=20;}這個介面非常簡單,就是包含一個結果清單和一些分頁的必要訊息,這裡要注意幾點:
1.這個介面的實作表示的是某一次查詢的某一頁數據,和上次查詢無關
2.這個介面的實作應該是唯讀的,也就是說不可以修改的。
3.getPages()方法是冗餘的,但這裡仍然提供這個方法。
下面給出一個抽象實作:
package treeroot.util;import java.util.List;/*** @author treerot* @version 1.0* @since 2004-9-30*/public abstract class AbstractPage implements Pageable{ private int currentPage; private int page intize; pages; protected int count; protected List result; /** * 指定目前頁* @param currentPage * @throws PageException */ public AbstractPage(int currentPage){ this(currentPage,Pageable.DEFAULT_PAGESIZE); } /** * 指定目前頁和頁大小* @param currentPage * @param pageSize * @throws PageException */ public AbstractPage(int currentPage,int pageSize) { this.currentPage=currentPage; this.pageSize=pageSize; } protected void checkPage(int currentPage) throws PageException{ if((currentPage<1)||(currentPage>. ) throw new PageException("頁超出範圍:總頁數為"+this.getPages()+",當前頁為"+currentPage); } /** * 這個方法被子類別重寫用來初始化,也就是計算count值和result結果,在子類別的建構子中呼叫。 */ abstract protected void init() throws PageException; public int getResult() { return result; } public int getCount() { return count; } public int getPageSize() { return pageSize; } public int; } public int getPages() { if(pages==0) this.pages=(count+pageSize-1)/pageSize; return pages; }}這個抽象類別實作了介面中的所有方法,但是定義了一個抽象方法init(),在子類別中必須實作這個方法。上面的一個介面和一個抽象類別看起來比較簡單,你可能會覺得好像什麼都沒有做,實現上確實沒有做什麼,但是卻可以給開發帶來很大的幫助。我們可以根據自己的需求要繼承這個抽象類,而資料可以透過各種方式取得,例如直接透過一個List取得,或是透過JDBC,Hibernate等等,不過我們都需要把結果封裝到一個List裡面,透過Hibernate就顯得特別方便了。
PageException是自訂的異常
package treeroot.util /*** @author treeroot* @version 1.0* @since 2004-9-30*/public class PageException extends Exception{ public PageException(){ super(); } public PageException(String message){ super( message); }}