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

JSP 結合 MySQL 實現分頁查詢的經典實現與優化

     編輯:關於JSP

分頁查詢在 Web 開發中的重要性

當資料量增長至數千甚至上萬筆時,一次性載入所有記錄會導致記憶體溢出、頁面渲染緩慢、用戶體驗極差。分頁查詢透過限制每次返回的記錄數,配合頁碼導航,成為 Web 應用處理大量資料的標準模式。本文以 JSP + MySQL 為例,詳細解析基於 JDBC 的分頁實現邏輯、代碼結構與效能優化方向。

核心分頁算法原理

傳統 JDBC 分頁採用「游標定位 + 限制筆數」策略:

  1. 執行 SELECT COUNT(*) 獲取總記錄數 totalRows。
  2. 計算總頁數:totalPages = (totalRows + pageSize - 1) / pageSize。
  3. 根據當前頁碼 currentPage 計算起始位置:offset = (currentPage - 1) * pageSize。
  4. 使用 ResultSet.TYPE_SCROLL_INSENSITIVE 建立可捲動結果集,調用 absolute(offset + 1) 定位游標,再循環讀取 pageSize 條記錄。

完整 JSP 實現代碼解析

1. 參數接收與邊界檢查

<%
    int pageSize = 10; // 每頁顯示筆數
    String pageParam = request.getParameter("page");
    int currentPage = 1;
    if (pageParam != null) {
        try { currentPage = Integer.parseInt(pageParam); }
        catch (NumberFormatException ignored) {}
    }
    if (currentPage < 1) currentPage = 1;
%>

2. 資料庫連接與查詢總筆數

<%
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection conn = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC",
        "user", "password");

    // 使用預編譯語句防止 SQL 注入
    PreparedStatement countStmt = conn.prepareStatement(
        "SELECT COUNT(*) FROM dxswlxh");
    ResultSet countRs = countStmt.executeQuery();
    countRs.next();
    int totalRows = countRs.getInt(1);
    countRs.close(); countStmt.close();

    int totalPages = (totalRows + pageSize - 1) / pageSize;
    if (currentPage > totalPages) currentPage = totalPages;
%>

3. 分頁查詢與結果展示

<%
    // MySQL 專用 LIMIT 語法(效能優於游標定位)
    String sql = "SELECT id, name, description FROM dxswlxh LIMIT ?, ?";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setInt(1, (currentPage - 1) * pageSize); // offset
    pstmt.setInt(2, pageSize);                     // limit
    ResultSet rs = pstmt.executeQuery();
%>

<table border="1" cellpadding="5" cellspacing="0">
    <tr><th>ID</th><th>名稱</th><th>描述</th></tr>
    <% while (rs.next()) { %>
    <tr>
        <td><%= rs.getInt("id") %></td>
        <td><%= rs.getString("name") %></td>
        <td><%= rs.getString("description") %></td>
    </tr>
    <% } %>
</table>

<% rs.close(); pstmt.close(); conn.close(); %>

4. 頁碼導航條構建

<div class="pagination">
    <a href="?page=1">首頁</a>
    <% if (currentPage > 1) { %>
        <a href="?page=<%= currentPage - 1 %>">上一頁</a>
    <% } %>
    
    <% 
        int start = Math.max(1, currentPage - 2);
        int end = Math.min(totalPages, currentPage + 2);
        for (int i = start; i <= end; i++) { %>
        <a href="?page=<%= i %>" class="<%= i==currentPage?'active':'' %>"><%= i %></a>
    <% } %>
    
    <% if (currentPage < totalPages) { %>
        <a href="?page=<%= currentPage + 1 %>">下一頁</a>
    <% } %>
    <a href="?page=<%= totalPages %>">尾頁</a>
    <span>第 <%= currentPage %> / <%= totalPages %> 頁,共 <%= totalRows %> 條</span>
</div>

效能優化關鍵點

避免使用可捲動結果集

原代碼使用 ResultSet.TYPE_SCROLL_INSENSITIVE 配合 absolute() 定位,此方式會將所有結果集載入記憶體,大數據量下極易導致 OOM。強烈建議改用數據庫原生分頁語法:

  • MySQL / PostgreSQL:LIMIT offset, pageSize
  • Oracle 12c+:OFFSET offset ROWS FETCH NEXT pageSize ROWS ONLY
  • SQL Server 2012+:OFFSET offset ROWS FETCH NEXT pageSize ROWS ONLY

連接池與資源管理

生產環境必須使用連接池(HikariCP、Druid、DBCP2),並利用 try-with-resources 確保連接、語句、結果集正確關閉:

try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // 處理結果集
} // 自動關閉資源

大偏移量深分頁問題

當 offset 極大時(如第 10000 頁),LIMIT 100000, 10 仍需掃描前 10 萬行。解決方案:

  • 基於游標/ID 的分頁:記住上一頁最大 ID,查詢 WHERE id > lastMaxId ORDER BY id LIMIT pageSize。
  • 延遲關聯:先只查主鍵 ID,再按 ID 列表關聯查試完整字段。

現代化架構建議

將分頁邏輯下沉至 DAO/Repository 層,JSP 僅負責渲染。引入分頁DTO對象封裝參數與結果:

public class PageResult<T> {
    private List<T> records;
    private long total;
    private int pageNum, pageSize;
    // getter/setter...
}

配合 MyBatis Plus、Spring Data JPA 等框架可進一步簡化分頁代碼,專注業務邏輯開發。

總結

JSP + MySQL 分頁查詢的核心在於「總數統計 + 限制查詢 + 頁碼導航」三步驟。雖然傳統 Scriptlet 寫法直觀,但存在業務邏輯與視圖耦合、資源洩漏風險、效能瓶頸等問題。現代開發應採用 MVC 分層、連接池、原生分頁語法、框架支撐,構建高效、可維護的分頁功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved