Mybatis--分页查询

news2024/11/15 22:11:47

一、分页查询

分页查询则是在页面上将本来很多的数据分段显示,每页显示用户自定义的行数。可提高用户体验度,同时减少一次性加载,内存溢出风险。

1、真假分页

分页分为:真分页和假分页。

 假分页:一次性查询所有数据存入内存,翻页从内存中获取数据。优点:实现简单,性能高;缺

点:容易造成内存溢出。

 真分页:每次翻页从数据库中查询数据。优点:不容易造成内存溢出;缺点:实现复杂,性能相对低。

2、分页效果

 当前页的结果集数据,比如这一页有哪些商品信息。

 分页条信息,比如包含【首页】【上页】【下页】【末页】等。

二、分页设计

从上面请求访问的分页演示的效果图分析分页是如何设计?

1、分页需传递的参数

需要用户传入的参数:

  currentPage:当前页,跳转到第几页,int 类型,设置默认值,比如 1

  pageSize:每页最多多少条数据,int 类型,设置默认值,比如 10

2、分页需展示的数据

从分页效果图中可以看出,分页需要依赖的数据:

当前页货品信息: data/list

 分页条信息:

beginPage

首页

prevPage

上一页

nextPage

下一页

totalPage

总页数/末页

totalCount/rows: 总条数

currentPage

当前页

pageSize

每页显示多少条数据

3、分页需展示的数据的来源

来源于用户传入:

currentPage

当前页,int 类型

pageSize

每页显示多少条数据,int 类型

来源于两条 SQL 查询:

totalCount/rows: 数据总条数,int 类型

data/list

每一页的结果集数据,List 类型

来源于程序计算:

totalPage

总页数/末页,int 类型

prevPage

上一页,int 类型

nextPage

下一页,int 类型

3.1、结果总数与结果集

结果总数(totalCount/rows)和结果集(data/list)是来源于两条 SQL(必须掌)的查询:

第一条 SQL:查询符合条件的结果总数(totalCount/rows

 第二条 SQL:查询符合条件的结果集(data/list

  • 第一个 ?:从哪一个索引的数据开始查询(默认从 0 开始)
  • 第二个 ?:查询多少条数据

SELECT * FROM 表名 [WHERE 条件] 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,即都来源于用户传递的分页参数。

3.2、总页数、上一页和下一页

总页数、上一页和下一页都是来源于程序计算出来的。

int totalPage = rows % pageSize == 0 ? rows / pageSize : rows / pageSize + 1;

  • 优先计算

int prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;

int nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;

三、分页查询实现

给产品增加分页查询的功能。

1、访问流程

2、分页数据封装

为了能在页面上显示上述的分页效果,那么我们就得在把页面上的每一个数据封装成到某个对象共享给JSP

2.1、为什么要封装

若不封装的话,会怎样,效果如下:

恶心:数据太分散,需要共享多个数据,不方便统一管理多个数据。

解决方案:把多个需要共享的数据,封装到一个对象,往后就只需要把数据封装到该对象,再共享该对象即可。

2.2、编写 PageResult.java

在之前 Web CRUD 项目的基础上增加新的代码即可。

/**

* 封装结果数据(某一页的数据)

*/

@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;

}

}

3、持久层分页功能实现

分页其最终的所有功能需要依赖的 SQL 就两条:

 查询数据的总数(为了显示分页条信息)。

 查询当前页的数据。

所以我们就得给 DAO 增加两个方法,一个查询数据总量,一个查询当前页的数据。

3.1、修改 IProductDAO.java

给其增加两个方法,分别用于查询结果总数和结果集。

int queryForCount(int currentPage, int pageSize);

List<Product> queryForList(int currentPage, int pageSize);

上述这样写的话方法是有两个形参的,但是 MyBatis 提供的操作方法传入执行 SQL 任务的参数,注意只能是一个,而现在两个参数需要传递两个分页的实参。

解决方案

方案一:使用 Map 来封装需要传递的参数。

方案二:使用 JavaBean 来封装需要传递的参数。

3.2、编写 QueryObject.java

目前用来封装分页参数,并解决上面的问题。

@Setter

@Getter

/**

  • 封装分页查询需要的两个请求传入的分页参数

*/

public class QueryObject {

private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)

private int pageSize = 3; // 每页显示条数(需要给默认值)

}

3.3、再修改 IProductDAO.java

修改分页查询的两个方法,改方法形参为 QueryObject

int queryForCount(QueryObject qo);

List<Product> queryForList(QueryObject qo);

3.4、修改 ProductDAOImpl.java

@Override

public int queryForCount(QueryObject qo) { SqlSession session = MyBatisUtil.getSession(); int totalCount =

session.selectOne("cn.mapper.ProductMapper.queryForCount", qo); session.close();

return totalCount;

}

@Override

public List<Product> queryForList(QueryObject qo) { SqlSession session = MyBatisUtil.getSession(); List<Product> products =

session.selectList("cn.mapper.ProductMapper.queryForList",qo); session.close();

return products;

}

3.5、修改 ProductMapper.xml

<select id="queryForCount" resultType="int"> SELECT COUNT(*) FROM product

</select>

<select id="queryForList" resultType="cn.domain.Product"> SELECT * FROM product LIMIT #{start}, #{pageSize}

</select>

3.6、修改 QueryObjet.java

 QueryObject 增加 getStart 方法,返回之前找出规律算出从那个位置开始查询数据,代码如下:

@Setter

@Getter

/**

  • 封装分页查询需要的两个请求传入的分页参数

*/

public class QueryObject {

private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)

private int pageSize = 3; // 每页显示条数(需要给默认值)

  • 用于 Limit 子句第一个 ? 取值 public int getStart(){

return (currentPage - 1) * pageSize;

}

}

3.7、编写单元测试

给测试类 ProductDAOTest 中添加分页测试的方法,测试一下。

@Test

public void testQueryForCount(){

QueryObject qo = new QueryObject();

System.out.println(productDAO.queryForCount(qo));

}

@Test

public void testQueryForList(){

QueryObject qo= new QueryObject();

System.out.println(productDAO.queryForList(qo));

}

4、业务层分页功能实现

 Servlet 调用,返回分页查询的结果,即返回 PageResult 对象,而形参类型为 QueryObject

4.1、编写 IProductService.java

public interface IProductService {

/**

  • 完成查询某一页的业务逻辑功能

*/

PageResult<Product> query(QueryObject qo);

}

4.2、编写 ProductServiceImpl.java

public class ProductServiceImpl implements IProductService {

private IProductDAO productDAO = new ProductDAOImpl();

@Override

public PageResult<Product> query(QueryObject qo) {

  • 调用 DAO 查询数据数量

int totalCount = productDAO.queryForCount(qo);

  • 为了性能加入判断,若查询的数据数量为 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);

}

}

4.3、编写单元测试类

 test 目录下的 cn.wolfcode.service 包下新建 ProductServiceTest 测试类,测试上面 query 方法,观察控制台输出结果。

public class ProductServiceTest {

private IProductService productService = new ProductServiceImpl();

@Test

public void testQuery(){

QueryObject qo= new QueryObject();

qo.setCurrentPage(1);

PageResult<Product> pageResult = productService.query(qo);

System.out.println("结果集数据:" + pageResult.getData());

System.out.println("当前页总记录数:" + pageResult.getTotalCount());

System.out.println("条数:" + pageResult.getData().size());

System.out.println("总页数:" + pageResult.getTotalPage());

System.out.println("上一页:" + pageResult.getPrevPage());

System.out.println("下一页:" + pageResult.getNextPage());

}

}

5、前台分页功能实现

包含编写 Servlet  JSPServlet 处理请求,调用业务方法,把查询到数据共享到 JSP 中,展示给用户看。

5.1、操作步骤

 必须先完成业务层组件,保证后台测试通过

 遵循 MVC 思想。

 浏览器发出分页请求参数(去往第几页/每页多少条数据),在 Servlet 中接收这些参数,并封装

 QueryObject 对象,调用 Service 中分页查询方法(query)。

 把得到的分页查询结果对象(PageResult)共享在请求作用域中,跳转到 JSP,显示即可。

 修改 JSP 页面,编写出分页条信息(分页条中的信息来源于 PageResult 对象)。

5.2、修改 ProductServlet.java

ProductServlet,获取页面传递的分页参数,执行查询,将结果共享到请求作用域,请求转发回到 list.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);

}

5.3、修改 list.jsp

在此 JSP 使用 JSTL + EL 获取后台共享到请求作用域中的数据,展示给用户看。

<%@ 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"><img src="${USER_IN_SESSION.headImg}" title="更换头像"/></a><br/>

<a href="/product?cmd=input">添加</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}">删除</a> <a href="/product?cmd=input&id=${product.id}">修改</a>

</td>

</tr>

</c:forEach>

<tr align="center">

<td colspan="9">

<a href="/product?currentPage=1">首页</a>

<a href="/product?currentPage=${pageResult.prevPage}">上一页

</a>

<a href="/product?currentPage=${pageResult.nextPage}">下一页

</a>

<a href="/product?currentPage=${pageResult.totalPage}">尾页

</a>

当前第 ${pageResult.currentPage} / ${pageResult.totalPage} 页一共 ${pageResult.totalCount} 条数据

跳转到<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>条数据

</td>

</tr>

</table>

</form>

</body>

</html>

四、常见问题

疑惑理解

  currentPage,表示要显示某一页数据的页码,在程序中表示翻页要去往的页面,比如

curentPage = 3,表示要跳转到第 3 页。

 上一页,下一页,末页是在 PageResult 的构造器中已经计算好。

常见问题:若刚开始翻页操作成功,但是翻几页之后就不能翻页了,只能重启 Tomcat 才可以翻页,但是操作几次又不能翻页了。问题原因:在 DAO 中没有关闭 SqlSession 对象释放资源。

Servlet 代码优化

protected void list(...) {

req2qo(req, qo);

// ......

}

  • 获取请求参数封装成对象

private void req2qo(HttpServletRequest req, QueryObject qo) {

String currentPage = req.getParameter("currentPage"); String pageSize = req.getParameter("pageSize");

if(StringUtil.hasLength(currentPage)) {

qo.setCurrentPage(Integer.valueOf(currentPage));

}

if(StringUtil.hasLength(pageSize)) {

qo.setPageSize(Integer.valueOf(pageSize));

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1940696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

笔记小结:卷积神经网络之多输入多输出通道

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 彩色图像具有标准的RGB通道来代表红、绿和蓝&#xff0c;需要三个通道表示&#xff0c;故而只有单输入单输出是不够的。 对于单个输入和单个输出通道的简化例子&…

Yolo-World网络模型结构及原理分析(一)——YOLO检测器

文章目录 概要一、整体架构分析二、详细结构分析YOLO检测器1. Backbone2. Head3.各模块的过程和作用Conv卷积模块C2F模块BottleNeck模块SPPF模块Upsampling模块Concat模块 概要 尽管YOLO&#xff08;You Only Look Once&#xff09;系列的对象检测器在效率和实用性方面表现出色…

【引领未来智造新纪元:量化机器人的革命性应用】

在日新月异的科技浪潮中&#xff0c;量化机器人正以其超凡的智慧与精准的操作&#xff0c;悄然改变着各行各业的生产面貌&#xff0c;成为推动产业升级、提升竞争力的关键力量。今天&#xff0c;让我们一同探索量化机器人在不同领域的广泛应用价值&#xff0c;见证它如何以科技…

CSA笔记4-包/源管理命令以及本地光盘仓库搭建

包/源管理命令 1.rpm是最基础的rmp包的安装命令&#xff0c;需要提前下载相关安装包和依赖包 2.yum/dnf是基于rpm包的自动安装命令&#xff0c;可以自动在仓库中匹配安装软件和依赖包 注意:以上是安装命令&#xff0c;以下是安装源 3.光盘源&#xff1a;是指安装系统时后的…

Air780EP- AT开发-阿里云应用指南

简介 使用AT方式连接阿里云分为一机一密和一型一密两种方式&#xff0c;其中一机一密又包括HTTP认证二次连接和MQTT直连两种方式 关联文档和使用工具&#xff1a; AT固件获取在线加/解密工具阿里云平台 准备工作 Air780EP_全IO开发板一套&#xff0c;包括天线SIM卡&#xff0…

华为云技术精髓笔记(四)-CES基础入门实战

华为云技术精髓笔记(四) CES基础入门实战 一、监控ECS性能 1、 远程登录ECS 步骤一 双击实验桌面的“Xfce终端”打开Terminal&#xff0c;输入以下命令登录云服务器。注意&#xff1a;请使用云服务器的公网IP替换命令中的【EIP】。 LANGen_us.UTF-8 ssh rootEIP说明&#x…

中国自然灾害影响及损失数据

自然灾害往往会导致大量的人员伤亡和财产损失&#xff0c;数据集详细记载了2014-2020年中国自然灾害影响以及灾害造成的损失情况。其中包括地震、台风、雨雪、阵雨、雪灾、暴雨、旱灾、龙卷风、泥石流、山崩、泥石流、滑坡、洪涝等灾害事件。 数据集主要以excel的格式存储。属性…

【学术会议征稿】第二届人工智能与自动化控制国际学术会议(AIAC 2024)

第二届人工智能与自动化控制国际学术会议&#xff08;AIAC 2024&#xff09; The 2nd International Conference on Artificial Intelligence and Automation Control 随着技术的迅猛发展&#xff0c;人工智能与自动化控制已经深入到工业、交通、医疗、教育等各个领域&#x…

【Linux】-----权限详解

目录 一、Linux下的权限概念 Ⅰ、是什么&#xff1f; Ⅱ、Linux下的两种角色 角色 如何添加普通用户 身份的转化方式 身份的提权 添加普通用户至白名单 二、Linux下的权限管理 Ⅰ、文件访问者的分类(Linux下的“人”) Ⅱ、文件类型和访问权限(事物属性) 1.文件类型 …

为什么阿里巴巴超级喜欢java开发?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「java的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 我猜可能是因为&#xff0…

GD32 MCU是如何进入中断函数的

用过GD32 MCU的小伙伴们都知道&#xff0c;程序是顺序执行的&#xff0c;但当有中断来的时候程序会跳转到中断函数&#xff0c;执行完中断函数后程序又继续回到原来的位置继续执行&#xff0c;那么你们知道MCU是如何找到中断函数入口的吗&#xff1f; 今天我们就以GD32F303系列…

MacOS M1 安装item2 并配置Zsh

文章目录 1 下载item22 美化item22.1 配置主题2.2 设置黑色的主题&#xff1a;2.3 配置显示状态栏 status bar 3 安装 Oh my zsh3.1 设置主题3.2 设置插件3.3 安装第三方插件1 下载仓库解压2 使用 git clone 一些常用插件以及其作用 参考 1 下载item2 MacOS自带终端&#xff0…

springboot个体快餐订单系统-计算机毕业设计源码13441

目 录 摘要 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 个体快餐订单系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 个…

ATA-7025高压放大器的参数特点与应用领域有哪些

高压放大器是一种电子设备&#xff0c;用于将低电压信号放大成高电压信号&#xff0c;其参数特点与应用领域有着广泛的应用。本文将从高压放大器的参数特点和主要应用领域两个方面展开详细介绍。 高压放大器的参数特点主要包括输入输出电压范围广、带宽宽、增益高、输出功率大等…

计网:物理层

写在开头&#xff1a;物理层就负责传送比特0和1&#xff0c; 本质上理解物理层就是理解传输介质哪个表示比特0和1&#xff0c;如&#xff1a;高电平表示1、低电平表示0等 物理层主要任务&#xff1a; 机械特性&#xff1a;指明接口所用接线器的形状和尺寸、引脚数目和排列、固…

数据结构之二元查找树转有序双向链表详解与示例(C/C++)

文章目录 1. 二元查找树&#xff08;BST&#xff09;简介2. 有序双向链表&#xff08;DLL&#xff09;简介3. 二元查找树的实现4. 转换为有序双向链表的步骤5. C实现代码6. C实现代码7. 效率与空间复杂度比较8. 结论 在数据结构与算法中&#xff0c;树和链表都是非常重要的数据…

八股文之java基础

jdk9中对字符串进行了一个什么优化&#xff1f; jdk9之前 字符串的拼接通常都是使用进行拼接 但是的实现我们是基于stringbuilder进行的 这个过程通常比较低效 包含了创建stringbuilder对象 通过append方法去将stringbuilder对象进行拼接 最后使用tostring方法去转换成最终的…

C# 基础语法(一篇包学会的)

C#&#xff08;读作"C Sharp"&#xff09;是一种现代的、通用的面向对象编程语言&#xff0c;由微软公司开发。它结合了C和C的强大特性&#xff0c;并去掉了一些复杂性&#xff0c;使得开发者可以更加高效地编写代码。 一、入坑C# (一) 安装和设置 首先&#xff0c…

Modbus转BACnet/IP网关BA100-配硬件说明

在现代自动化系统中&#xff0c;不同设备和系统之间的通信至关重要&#xff0c;Modbus和BACnet/IP协议虽然各有优势&#xff0c;但它们之间的直接通信存在障碍。钡铼Modbus转BACnet/IP网关作为连接这两种协议的桥梁&#xff0c;允许不同系统之间的无缝数据交换。 一、Modbus转…

喜讯丨泰迪智能科技实力中标湖北民族大学数学与统计学院一流专业实验室建设项目

近日&#xff0c;泰迪智能科技凭借其卓越的技术实力与解决方案&#xff0c;在湖北民族大学数学与统计学院的一流专业实验室建设项目招标中脱颖而出&#xff0c;成功揽获该项目的建设权&#xff0c;中标项目金额达人民币355万元。 项目建设成果 一、实验室建设内容&#xff1a; …