用了這么久的PageHelper,你知道原生的分頁查詢原理和步驟嗎
你知道的越多,不知道的就越多,業(yè)余的像一棵小草!
成功路上并不擁擠,因為堅持的人不多。
編輯:業(yè)余草
juejin.cn/post/6987553953156169742
推薦:https://www.xttblog.com/?p=5249
一、分頁查詢概述
分頁查詢則是在頁面上將本來很多的數(shù)據(jù)分段顯示,每頁顯示用戶自定義的行數(shù)??商岣哂脩趔w驗度,同時減少一次性加載,內存溢出風險。
1.1、分頁查詢分類
1.1.1、真分頁
每次翻頁從數(shù)據(jù)庫中查詢數(shù)據(jù)。
優(yōu)點:不容易造成內存溢出。 缺點:實現(xiàn)復雜,性能相對低。
1.1.2、假分頁
一次性查詢所有數(shù)據(jù)存入內存,翻頁從內存中獲取數(shù)據(jù)。
優(yōu)點:實現(xiàn)簡單,性能高。 缺點:容易造成內存溢出。
1.2、分頁效果
發(fā)送請求訪問一個帶有分頁頁面的數(shù)據(jù),會發(fā)現(xiàn)其主要由兩部分組成:
當前頁的結果集數(shù)據(jù),比如這一頁有哪些商品信息。 分頁條信息,比如包含【首頁】【上頁】【下頁】【末頁】等。

二、分頁的設計
2.1、分頁需要傳遞的參數(shù)
2.1.1、用戶需要傳入的參數(shù)
currentPage:當前頁,跳轉到第幾頁,int 類型,設置默認值,比如 1。 pageSize:每頁最多多少條數(shù)據(jù),int 類型,設置默認值,比如 10。
2.1.2、分頁需要展示的數(shù)據(jù)
start:首頁。 prevPage:上一頁。 nextPage:下一頁。 totalPage:末頁頁碼。 totalCounts:總記錄數(shù)。 currentPage:當前頁。 pageSize:每頁記錄數(shù)。
2.1.3、分頁需展示的數(shù)據(jù)的來源
來源于用戶傳入:
currentPage:當前頁,int 類型。
pageSize:每頁顯示多少條數(shù)據(jù),int 類型。
來源于兩條 SQL 查詢:
totalCount/rows:數(shù)據(jù)總條數(shù),int 類型。 data/list:每一頁的結果集數(shù)據(jù),List 類型。 來源于程序計算:
totalPage:總頁數(shù)/末頁,int 類型。 prevPage:上一頁,int 類型。 nextPage:下一頁,int 類型。
2.2、分頁原理
結果總數(shù)(totalCount/rows)和結果集(data/list)是來源于兩條 SQL:
第一條SQL:查詢總數(shù),返回一個數(shù)字(總記錄數(shù))。
select count(*) from province
查詢符合條件的結果集(返回一個結果集)。
# 他有兩個參數(shù),一個是起始頁的頁碼,另一個是每頁記錄數(shù)
# start :(currentPage - 1) * pageSize
# pageSize:前臺給予
select * from province limit #{start} ,#{pageSize}
計算出其余的參數(shù)(總頁數(shù)、上一頁、下一頁)
// 分頁數(shù)據(jù)通過這個構造器封裝好
public PageResult(int currentPage, int pageSize, int totalCount, List<T> data) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.data = data;
// 計算總頁數(shù)(要先算)
this.totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
// 利用三元運算符來計算上一頁,如果已經(jīng)是第一頁的話,那么他就不會有上一頁,讓他的上一頁為第一頁,否則就當前頁減1為上一頁
this.prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;
// 利用三元運算符計算下一頁,如果已經(jīng)是最后一頁的話,那么就沒有下一頁了,就不讓他下一頁再增加,否則就當前頁自增
this.nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;
}
三、分頁查詢實現(xiàn)
3.1、訪問流程

3.2、分頁參數(shù)的封裝
為了能在頁面上顯示上述的分頁效果,那么我們就得在把頁面上的每一個數(shù)據(jù)封裝成到某個對象共享給
JSP。
如果我們不進行封裝的話,那么這個七個參數(shù)要全部在Session域中去取,比較復雜和惡心。
我們一般會把多個需要共享的數(shù)據(jù),封裝到一個對象,往后就只需要把數(shù)據(jù)封裝到該對象,再共享該對象即可。
3.3、編寫PageResult
package com.qo;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
/**
封裝結果數(shù)據(jù)(某一頁的數(shù)據(jù))
* @author Xiao_Lin
*/
public class PageResult<T> {
// 用戶輸入的數(shù)據(jù)
private int currentPage; // 當前頁碼
private int pageSize; // 每頁顯示的條數(shù)
//SQL執(zhí)行后的結果
private int totalCount; // 總條數(shù)
private List<T> data; // 當前頁數(shù)據(jù)結果集
// 利用程序計算出來的
private int prevPage; // 上一頁
private int nextPage; // 下一頁
private int totalPage; // 最后一頁
// 分頁數(shù)據(jù)通過這個構造器封裝好
public PageResult(int currentPage, int pageSize, int totalCount, List<T> data) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.data = data;
// 計算總頁數(shù)(要先算)
this.totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
// 利用三元運算符來計算上一頁,如果已經(jīng)是第一頁的話,那么他就不會有上一頁,讓他的上一頁為第一頁,否則就當前頁減1為上一頁
this.prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;
// 利用三元運算符計算下一頁,如果已經(jīng)是最后一頁的話,那么就沒有下一頁了,就不讓他下一頁再增加,否則就當前頁自增
this.nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;
}
}
3.4、修改Mapper(Dao)
// 查詢總記錄數(shù),傳入一個封裝好的查詢對象,里面的參數(shù)有當前頁、每頁記錄數(shù)(可不傳,盡量傳,為模糊查詢做基礎)
int queryCount(QueryObject qo);
// 查詢結果集,傳入一個封裝好的查詢對象,里面封裝好的參數(shù)有當前頁、每頁記錄數(shù)、起始頁頁碼
List<Province> query(QueryObject qo);
3.5、修改Service以及ServiceImpl
PageResult<Province> query(ProvinceQueryObject qo);
package com.service.impl;
/**
* @author 業(yè)余草
*/
public class ProvinceServiceImpl implements ProvinceService {
ProvinceMapper mapper = ConnUtils.getConnection().getMapper(ProvinceMapper.class);
@Override
public PageResult<Province> query(ProvinceQueryObject qo) {
// 獲取查詢的記錄數(shù)
int totalCount = mapper.queryCount(qo);
// 如果總記錄數(shù)為0,那么說明沒數(shù)據(jù)就不用下一步查詢了,提高效率。
if (totalCount == 0){
// 返回一個查詢結果集,返回當前頁、每頁記錄數(shù)、以及一個空的結果集
return new PageResult<Province>(qo.getCurrentPage(),qo.getPageSize(),totalCount,Collections.EMPTY_LIST);
}
// 記錄數(shù)不為0,查詢出一個結果集
List<Province> provinces = mapper.query(qo);
// 返回一個查詢結果集,返回當前頁、每頁記錄數(shù)、以及結果集
return new PageResult<Province>(qo.getCurrentPage(),qo.getPageSize(),totalCount,provinces);
}
3.6、編寫QueryObject
package com.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 封裝分頁查詢需要的兩個請求傳入的分頁參數(shù)
* @author 業(yè)余草
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryObject {
private int currentPage = 1; // 當前頁碼,要跳轉到哪一頁的頁碼(需要給默認值)
private int pageSize = 3 ; // 每頁顯示條數(shù)(需要給默認值)
//用于 Limit 子句第一個 ? 取值,起始頁頁碼
public int getStart(){
return (currentPage-1)*pageSize;
}
}
3.7、編寫測試類
ProvinceService provinceService = new ProvinceServiceImpl();
QueryObject qo = new QueryObject();
PageResult<Province> pageResult = provinceService.query(qo);
System.out.println("當前頁:"+pageResult.getCurrentPage());
System.out.println("結果集數(shù)據(jù):" + pageResult.getData());
System.out.println("當前頁總記錄數(shù):" + pageResult.getTotalCount());
System.out.println("條數(shù):" + pageResult.getData().size());
System.out.println("總頁數(shù):" + pageResult.getTotalPage());
System.out.println("上一頁:" + pageResult.getPrePage());
System.out.println("下一頁:" + pageResult.getNextPage());

3.7、編寫Servlet
package com.servlet;
/**
* @author 業(yè)余草
*/
@WebServlet(urlPatterns = "/listall")
public class ProvinceServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ProvinceService provinceService = new ProvinceServiceImpl();
// 創(chuàng)建QueryObject對象
QueryObject qo = new QueryObject();
// 獲取參數(shù)
String currentPage = req.getParameter("currentPage");
// 利用工具類判斷是否傳了這個參數(shù)
if (StringUtil.hasLength(currentPage)){
// 如果傳了就賦值
qo.setCurrentPage(Integer.parseInt(currentPage));
}
String pageSize = req.getParameter("pageSize");
if (StringUtil.hasLength(pageSize)){
qo.setPageSize(Integer.parseInt(pageSize));
}
// 調用業(yè)務層方法來處理請求查詢某一頁數(shù)據(jù)
PageResult<Province> query = provinceService.query(qo);
// 把數(shù)據(jù)共享給jsp
req.setAttribute("pageResult", query);
// 控制跳轉到 list.jsp 頁面
req.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(req, resp);
}
}
3.7、前臺實現(xiàn)
包含編寫 Servlet 及 JSP,Servlet 處理請求,調用業(yè)務方法,把查詢到數(shù)據(jù)共享到 JSP 中,展示給用戶。操作步驟:
瀏覽器發(fā)出分頁請求參數(shù)(去往第幾頁/每頁多少條數(shù)據(jù)),在 Servlet 中接收這些參數(shù),并封裝 到 QueryObject 對象,調用 Service 中分頁查詢方法(query)。 把得到的分頁查詢結果對象(PageResult)共享在請求作用域中,跳轉到 JSP,顯示即可。 修改 JSP 頁面,編寫出分頁條信息(分頁條中的信息來源于 PageResult 對象)。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>產品列表</title>
<script type="text/javascript">
window.onload = function () {
var trClzs = document.getElementsByClassName("trClassName");
for(var i = 0; i < trClzs.length; i++){
trClzs[i].onmouseover = function () {
console.log(1);
this.style.backgroundColor = "gray";
}
trClzs[i].onmouseout = function () {
console.log(2);
this.style.backgroundColor = "";
}
}
}
// 分頁 JS
function changePageSize() {
document.forms[0].submit();
}
</script>
</head>
<body>
<form action="/product">
<table border="1" cellspacing="0" cellpadding="0" width="80%">
<tr>
<th>編號</th>
<th>名稱</th>
<th>簡稱</th>
</tr>
<c:forEach var="province" items="${pageResult.data}"
varStatus="status">
<tr class="trClassName">
<td>${status.count}</td>
<td>${province.id}</td>
<td>${province.name}</td>
<td>${province.abbr}</td>
<td>
<a href="/listall?cmd=delete&id=${product.id}">刪除</a>
<a href="/listall?cmd=input&id=${product.id}">修改</a>
</td>
</tr>
</c:forEach>
<tr align="center">
<td colspan="9">
<a href="/listall?currentPage=1">首頁</a>
<a href="/listall?currentPage=${pageResult.prevPage}">上一頁
</a>
<a href="/listall?currentPage=${pageResult.nextPage}">下一頁
</a>
<a href="/listall?currentPage=${pageResult.totalPage}">尾頁
</a>
當前第 ${pageResult.currentPage} / ${pageResult.totalPage} 頁
一共 ${pageResult.totalCount} 條數(shù)據(jù)
跳轉到<input type="number" onchange="changePageSize()"
name="currentPage" value="${pageResult.currentPage}" style="width: 60px;">頁
每頁顯示
<select name="pageSize" onchange="changePageSize()">
<option value="3" ${pageResult.pageSize == 3 ?
'selected' : ''}> 3 </option>
<option value="5" ${pageResult.pageSize == 5 ?
'selected' : ''}> 5 </option>
<option value="8" ${pageResult.pageSize == 8 ?
'selected' : ''}> 8 </option>
</select>條數(shù)據(jù)
</td>
</tr>
</table>
</form>
</body>
</html>評論
圖片
表情
