首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate 實現 Struts 分頁查詢的最佳實踐

     編輯:Java 相關知識

分頁策略對比

在 Web 應用開發中,分頁處理是核心需求。主要有兩種架構模式:

  1. 全量查詢 + 前端分頁:Action 層一次性查出所有記錄放入 Session/Request,由 JSP 切片顯示。適合數據量極小(<1000 條)的場景,開發簡單但記憶體佔用大。
  2. 數據庫級分頁:每次只查詢當前頁所需記錄。適合大數據量系統,雖增加請求次數,但大幅降低內存壓力與網絡傳輸開銷。

本文採用方案二,結合 Hibernate 原生 setFirstResult()/setMaxResults() 實現高效分頁。

Hibernate 分頁核心 API

Query q = session.createQuery("from Cat as c");
q.setFirstResult(10000); // 跳過前 10000 條
q.setMaxResults(100);    // 取 100 條
List list = q.list();

核心組件設計

1. Pager 分頁模型

封裝總行數、頁大小、當前頁、總頁數、起始行等屬性,提供首頁、上頁、下頁、尾頁、跳轉等導航邏輯:

package com.jpcf.db.helper;

public class Pager {
    private int totalRows, pageSize = 10, currentPage, totalPages, startRow;

    public Pager(int totalRows) {
        this.totalRows = totalRows;
        this.totalPages = (totalRows + pageSize - 1) / pageSize;
        this.currentPage = 1;
        this.startRow = 0;
    }

    // 導航方法
    public void first() { currentPage = 1; startRow = 0; }
    public void previous() { if (currentPage > 1) { currentPage--; startRow = (currentPage - 1) * pageSize; } }
    public void next() { if (currentPage < totalPages) { currentPage++; startRow = (currentPage - 1) * pageSize; } }
    public void last() { currentPage = totalPages; startRow = (currentPage - 1) * pageSize; }
    public void refresh(int page) { currentPage = Math.min(page, totalPages); startRow = (currentPage - 1) * pageSize; }

    // Getter/Setter 省略...
}

2. PagerHelper 請求解析器

從 HTTP 請求參數中提取分頁狀態,自動計算並返回填充好的 Pager 實例:

package com.jpcf.db.helper;

import javax.servlet.http.HttpServletRequest;

public class PagerHelper {
    public static Pager getPager(HttpServletRequest request, int totalRows) {
        Pager pager = new Pager(totalRows);
        String currentPage = request.getParameter("currentPage");
        if (currentPage != null) pager.refresh(Integer.parseInt(currentPage));

        String method = request.getParameter("pageMethod");
        if (method != null) {
            switch (method) {
                case "first": pager.first(); break;
                case "previous": pager.previous(); break;
                case "next": pager.next(); break;
                case "last": pager.last(); break;
            }
        }
        return pager;
    }
}

3. DAO 層分頁查詢

package com.jpcf.db.dao;

import com.jpcf.db.helper.HibernateUtil;
import net.sf.hibernate.*;
import java.util.*;

public class VehiclePropertyDAO {
    /** 分頁查詢 */
    public Collection findWithPage(int pageSize, int startRow) throws HibernateException {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();
        try {
            Query q = session.createQuery("from VehicleProperty vp");
            q.setFirstResult(startRow);
            q.setMaxResults(pageSize);
            List list = q.list();
            tx.commit();
            return list;
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            throw e;
        } finally {
            HibernateUtil.closeSession();
        }
    }

    /** 統計總行數 */
    public int getRows(String hql) throws HibernateException {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();
        try {
            Integer count = (Integer) session.iterate(hql).next();
            tx.commit();
            return count.intValue();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            throw e;
        } finally {
            HibernateUtil.closeSession();
        }
    }
}

4. Action 處理流程

public ActionForward queryWithPage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) {
    VehiclePropertyDAO dao = new VehiclePropertyDAO();
    int totalRows;
    try {
        totalRows = dao.getRows("select count(*) from VehicleProperty");
    } catch (Exception e) {
        servlet.log(e.toString());
        return mapping.findForward(Constants.FAILURE);
    }

    Pager pager = PagerHelper.getPager(request, totalRows);
    Collection list;
    try {
        list = dao.findWithPage(pager.getPageSize(), pager.getStartRow());
    } catch (Exception e) {
        servlet.log(e.toString());
        return mapping.findForward(Constants.FAILURE);
    }

    request.setAttribute("CLINFOS", list);
    request.setAttribute("PAGER", pager);
    return mapping.findForward(Constants.SUCCESS);
}

5. JSP 頁面導航

使用 Struts 標簽庫生成分頁鏈接,傳遞 pageMethod 與 currentPage 參數:

<html:link action="/bussiness/clInfo/queryWithPage.do" paramId="currentPage" paramName="PAGER" paramProperty="currentPage">
    <html:param name="pageMethod" value="first"/>首頁
</html:link>
<html:link ...><html:param name="pageMethod" value="previous"/>上一頁</html:link>
<html:link ...><html:param name="pageMethod" value="next"/>下一頁</html:link>
<html:link ...><html:param name="pageMethod" value="last"/>尾頁</html:link>

優化建議

  • 將 HQL 語句作為參數傳入 DAO,提高複用性。
  • 引入緩存機制緩存總行數,避免每次分頁都執行 count(*)。
  • 考慮使用 ScrollableResults 游標模式處理超大結果集。
  • 現代項目建議遷移至 Spring Data JPA + Pageable 或 MyBatis PageHelper,簡化分頁代碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved