分頁查詢將資料庫中龐大的資料分段顯示,每頁顯示使用者自訂的行數,提高使用者體驗度,最主要的是如果一次從伺服器磁碟中讀取出全部資料到記憶體,有記憶體溢出的風險
假分頁: 其原理還是將所有的資料讀到記憶體,翻頁從記憶體讀取資料,優點: 實作簡單,效能高缺點:如果資料大容易造成記憶體溢位
真分頁: 每次翻頁從資料庫查詢資料(即磁碟) , 優點: 不容易造成記憶體溢位缺點: 實作複雜,效能相對低一些
一般分頁的功能包括: 首頁上一頁下一頁末頁當前是多少頁總共多少頁一共多少行資料跳到第幾頁每頁多少資料列資料我們需要將這個資料查詢出來封裝到一個物件中,體現了封裝想法,也節省了很多複雜程式碼
分頁需要傳遞的參數
需要使用者傳入的參數:
currentPage: 當前頁,跳到第幾頁, 第一次存取,我們建立一個物件,預設值為1
pageSize: 每頁顯示多少行資料, 第一次我們也給個預設值例如10條
分頁需要展示的資料
1.目前頁的貨品資訊
2.首頁是第幾頁
3.上一頁是第幾頁
4.下一頁是第幾頁
5.一共有多少頁,和末頁的值是一樣的
6.資料總共有多少條(行)
7.目前是第幾頁
8.每頁顯示多少條資訊
分頁需要展示的資料的來源
來自用戶上傳: 當前頁, 每頁顯示多少條資料
來自資料庫查詢: 資料總條數, 每一頁需要展示的商品資訊
來自上面的已知資訊計算: 總頁數, 上一頁, 下一頁
書寫從資料庫查詢的sql語句
##第一條sql 查詢資料庫中有多少條資料,COUNT後面不能有空格SELECT COUNT(*) FROM 表名第二條sql 根據傳入的參數查詢第幾頁,一頁多少條資料的結果集
# 第一个 ?:从哪一个索引的数据开始查询(默认从 0 开始) # 第二个 ?:查询多少条数据 SELECT * FROM 表名 LIMIT ?, ?接下來分析第二條SQL 中兩個? 取值來源:
假設product 表中有21 個數據,每頁分5 個數據:
查詢第一頁數據:SELECT * FROM product LIMIT 0, 5
查詢第二頁資料:SELECT * FROM product LIMIT 5, 5
查詢第三頁資料:SELECT * FROM product LIMIT 10, 5
查詢第四頁資料:SELECT * FROM product LIMIT 15, 5
透過尋找規律發現:第一個? 取值來自(currentPage - 1) * pageSize;第二個? 取值來自
pageSize,即都來自使用者傳遞的分頁參數。
總頁數,上一頁與下一頁
// 优先计算总页数 int totalPage = rows % pageSize == 0 ? rows / pageSize : rows / pageSize + 1; //上一页等于当前页-1,但不能超过1页界限 int prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1; //下一页等于当前页+1,但不能超过总页数界限 int nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;
#分頁查詢實作##存取流程:
封裝需要展示的資料如果不封裝資料,每個資料都需要存到作用域,資料太分散,不方便統一管理
/** * 封装结果数据(某一页的数据) */ @Getter public class PageResult<T> { // 两个用户的输入 private int currentPage; // 当前页码 private int pageSize; // 每页显示的条数 // 两条 SQL 语句执行的结果 private int totalCount; // 总条数 private List<T> data; // 当前页结果集数据 // 三个程序计算的数据 private int prevPage; // 上一页页码 private int nextPage; // 下一页页码 private int totalPage; // 总页数/末页页码 // 分页数据通过下面构造期封装好 public PageResult(int currentPage, int pageSize, int totalCount, List<T> data) { this.currentPage = currentPage; this.pageSize = pageSize; this.totalCount = totalCount; this.data = data; // 计算三个数据 this.totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1; this.prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1; this.nextPage = currentPage + 1 <= this.totalPage ? currentPage + 1 : this.totalPage; } }持久層DAO
Mybatis提供的操作方法只能傳入一個參數執行SQL任務,而我們現在查詢某一頁的數據,需要知道是第幾頁和每頁多少條資料這兩個參數,所以我們需要將這兩個參數封裝在一個物件裡面
編寫一個類別(起名叫查詢物件類別)來封裝這些查詢資料@Setter @Getter /** * 封装分页查询需要的两个请求传入的分页参数 */ public class QueryObject { private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值) private int pageSize = 3; // 每页显示条数(需要给默认值) }
//DAO接口提供两个根据查询对象的查询方法 int queryForCount(); List<Product> queryForList(QueryObject qo); //DAO实现类 @Override //查询数据库总数据条数 public int queryForCount() { SqlSession session = MyBatisUtil.getSession(); int totalCount = session.selectOne("cn.xxx.mapper.ProductMapper.queryForCount"); session.close(); return totalCount; } @Override //查询某一页的结果集 public List<Product> queryForList(QueryObject qo) { SqlSession session = MyBatisUtil.getSession(); List<Product> products = session.selectList("cn.xxx.mapper.ProductMapper.queryForList",qo); session.close(); return products; }
修改productMapper.xml
<select id="queryForCount" resultType="int"> SELECT COUNT(*) FROM product </select> <select id="queryForList" resultType="cn.xxx.domain.Product"> SELECT * FROM product LIMIT #{start}, #{pageSize} </select>
修改QueryObject.java
#給這個類別增加getStart方法,返回根據當前頁,每頁大小需要從資料庫從第幾行開始顯示
@Setter @Getter /** * 封装分页查询需要的两个请求传入的分页参数 */ public class QueryObject { private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值) private int pageSize = 3; // 每页显示条数(需要给默认值) // 用于 Limit 子句第一个 ? 取值 public int getStart(){ return (currentPage - 1) * pageSize; } }業務層ProductService
調用持久層DAO完成資料的查詢,並將多個資料封裝到一個物件中
//IProductService接口 public interface IProductService { /** * 完成查询某一页的业务逻辑功能 */ PageResult<Product> query(QueryObject qo); } //Service实现类 public class ProductServiceImpl implements IProductService { private IProductDAO productDAO = new ProductDAOImpl(); @Override public PageResult<Product> query(QueryObject qo) { // 调用 DAO 查询数据数量 int totalCount = productDAO.queryForCount(); // 为了性能加入判断,若查询的数据数量为 0,说明没有数据,返回返回空集合,即集合中没有 元素 if(totalCount == 0){ return new PageResult(qo.getCurrentPage(), qo.getPageSize(), totalCount, Collections.emptyList()); } // 执行到这里代表有数据,查询当前页的结果数据 List<Product> products = productDAO.queryForList(qo); return new PageResult(qo.getCurrentPage(), qo.getPageSize(), totalCount, products); } }前台分頁功能實作
1.必須先完成業務層元件,確保後台測試通過。
2.遵循 MVC 思想。3.瀏覽器發出分頁請求參數(去往第幾頁/每頁多少條資料),在Servlet 中接收這些參數,並封裝
4.到QueryObject 對象,呼叫Service 中分頁查詢方法( query)。
5.把得到的分頁查詢結果物件(PageResult)共用在請求作用域中,跳到 JSP,顯示即可。
6.修改 JSP 頁面,寫出分頁條資訊(分頁條中的資訊來自 PageResult 物件)。
#1.取得頁面請求參數,判斷是查詢操作,呼叫查詢方法,取得分頁參數
2.將參數封裝成查詢物件QueryObject3.呼叫業務層方法查詢某一頁資料
4.將查詢出來的結果存到作用域中
5.轉送到展示頁面jsp
6.在jsp從作用域中將結果取出來回應到瀏覽器
//创建业务层对象 private IProductService productService = new ProductServiceImpl(); protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { QueryObject qo = new QueryObject(); // 获取请求参数 currentPage,并转型封装 String currentPage = req.getParameter("currentPage"); if(StringUtil.hasLength(currentPage)) { qo.setCurrentPage(Integer.valueOf(currentPage)); } // 获取请求参数 pageSize,并转型封装 String pageSize = req.getParameter("pageSize"); if(StringUtil.hasLength(pageSize)) { qo.setPageSize(Integer.valueOf(pageSize)); } // 调用业务层方法来处理请求查询某一页数据 PageResult<Product> pageResult = productService.query(qo); // 把数据共享给 list.jsp req.setAttribute("pageResult", pageResult); // 控制跳转到 list.jsp 页面 req.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(req, resp); }
<%@ 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> <a href="/replaceImg.jsp" rel="external nofollow" ><img src="${USER_IN_SESSION.headImg}" title="更换头 像"/></a><br/> <a href="/product?cmd=input" rel="external nofollow" >添加</a> <form action="/product"> <table border="1" cellspacing="0" cellpadding="0" width="80%"> <tr> <th>编号</th> <th>货品名</th> <th>分类编号</th> <th>零售价</th> <th>供应商</th> <th>品牌</th> <th>折扣</th> <th>进货价</th> <th>操作</th> </tr> <c:forEach var="product" items="${pageResult.data}" varStatus="status"> <tr class="trClassName"> <td>${status.count}</td> <td>${product.productName}</td> <td>${product.dir_id}</td> <td>${product.salePrice}</td> <td>${product.supplier}</td> <td>${product.brand}</td> <td>${product.cutoff}</td> <td>${product.costPrice}</td> <td> <a href="/product?cmd=delete&id=${product.id}" rel="external nofollow" >删除</a> <a href="/product?cmd=input&id=${product.id}" rel="external nofollow" >修改</a> </td> </tr> </c:forEach> <tr align="center"> <td colspan="9"> <a href="/product?currentPage=1" rel="external nofollow" >首页</a> <a href="/product?currentPage=${pageResult.prevPage}" rel="external nofollow" >上一页</a> <a href="/product?currentPage=${pageResult.nextPage}" rel="external nofollow" >下一页</a> <a href="/product?currentPage=${pageResult.totalPage}" rel="external nofollow" >尾页</a> 当前第 ${pageResult.currentPage} / ${pageResult.totalPage} 页 一共 ${pageResult.totalCount} 条数据 跳转到<input type="number" onchange="changePageSize()" name="currentPage" value="${pageResult.currentPage}" 页 每页显示 <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>条数据 </td> </tr> </table> </form> </body> </html>常見問題
若開始翻頁操作成功,翻了幾頁不能翻了,只能重啟tomcat才能翻,問題: DAO中沒有關閉SqlSession物件
以上是怎麼用Java實作分頁查詢功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!