2007年8月26日 星期日

分頁效能的實作

Displaytag 有一個常見的 issue, 就是在撈出大量資料時, 會出現 Outofmemory 的錯誤.
因為 displaytag 的預設值, 是將所有的資料一次撈到記憶體, 再執行分頁的動作, 然而這樣的作法是相當消耗記憶體的, 也容易引起exception.
在 displaytag 1.1 版本中(若您的版本是1.0, 請記得切換至1.1), 我們只需要幾個簡單的設定, 就可以改善這個狀況.

先看下列的設定:

<display:table id="row" name="RESULT_LIST" partialList="true" requestURI=""
class="list" pagesize="10" size="${RESULT_SIZE}">

基本上跟 display tag1.0 無太大差異, 但是請記得將 partialList="true" 加入, 表示 displaytag 開啟了有限制的分頁機制,
而 pagesize 為每頁的 record 數目, size 則為資料的總筆數. 該機制與以前最大的不同, 就是只抓取 pagesize 所指定的數量
(該例為10筆, 也就是一次只取出十個物件).

為了確切的達成分頁功能, 我們還需要幾個實作,
先看 Controller 的部分:
...
int pageIndex = getPageIndex(request, getPageIndexName("row"));
//利用 displaytag 的屬性 id="row", 取得目前在第幾頁

int resultSize = dao.getAllCount();
//總共的筆數

List list = dao.search(pageIndex, pageSize);
//目前的筆數

....
request.setAttribute("RESULT_SIZE", new Integer(resultSize));
request.setAttribute("RESULT_LIST", list);

在這個例子當中, 要注意的是 pageIndex 利用到兩個 mtehod getPageIndexName(),
getPageIndex(), 其用意即註解所示, 取得當前的頁數, 詳細實作如下:
....

import org.apache.commons.validator.GenericValidator;
import org.displaytag.util.ParamEncoder;
import org.displaytag.tags.TableTagParameters;

public static String getPageIndexName(String encoder) {
String pageIndexName = new ParamEncoder(encoder).
encodeParameterName(TableTagParameters.PARAMETER_PAGE);
return pageIndexName;
}

public static int getPageIndex(HttpServletRequest request, String pageIndexName) {
int pageIndex = GenericValidator.isBlankOrNull(request.getParameter(pageIndexName)) ? 0
:(Integer.parseInt(request.getParameter(pageIndexName)) - 1 );
return pageIndex;
}
....

而在 dao.getAllCount(), dao.search(), 這兩個呼叫當中, 是為了分別取得總筆數及目前的筆數,
當然 DAO 層的實作可能依照您的 persistence, 而有所不同.

若 dao.search() 是利用 Hibernate 實作的, 範例大致如下:
....
public List search(int pageIndex, int pageSize){
List values;

String hql = "from Person";
Query query = getSession().createQuery(hql);

if (pageIndex >= 0) {
query.setFirstResult(pageSize * pageIndex);
}

if (pageSize > 0) {
query.setMaxResults(pageSize);
}

values = query.list();

return values;
}
....

0 意見: