JAVA-分页查询

news2025/1/22 17:46:27

分页查询

分页查询将数据库中庞大的数据分段显示,每页显示用户自定义的行数,提高用户体验度,最主要的是如果一次性从服务器磁盘中读出全部数据到内存,有内存溢出的风险

真假分页

假分页: 其原理还是将所有的数据读到内存中,翻页从内存中读取数据,
优点: 实现简单,性能高
缺点:如果数据大容易造成内存溢出

真分页: 每次翻页从数据库查询数据(即磁盘)
优点 : 不容易造成内存溢出
缺点: 实现复杂,性能相对低一些

分页效果

一般分页的功能包括: 首页 上一页 下一页 末页 当前是多少页 总共多少页 一共多少行数据 跳转到第几页 每页多少条数据 我们需要将这个数据查询出来封装到一个对象中,体现了封装思想,也节省了很多复杂代码在这里插入图片描述

分页的设计

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

分页需要传递的参数

需要用户传入的参数:

  • currentPage: 当前页,跳转到第几页,如第一次访问默认值是1
  • pageSize: 每页显示多少行数据, 如第一次访问默认值 10条

分页需要展示的数据

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

  1. 当前页的货品信息(也就是商品的集合数据)
  2. 分页条信息:
    • beginPage: 首页
    • prevPage: 上一页
    • nextPage: 下一页
    • totalPage: 总页数/末页
    • totalCount/rows: 总条数
    • currentPage: 当前页
    • pageSize: 每页显示多少条数据

分页需要展示的数据的来源

来源于用户上传: 当前页 , 每页显示多少条数据
来源于数据库查询 : 数据总条数 , 每一页需要展示的商品集合信息
来源于根据上面的已知信息在代码中计算 : 总页数 , 上一页 , 下一页

查询结果总数与结果集的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分页功能实现

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

  • 查询数据的总数(为了显示分页条信息)。
  • 查询当前页的数据。
    所以我们就得给 DAO 增加两个方法,一个查询数据总量,一个查询当前页的商品数据集合。

Mybatis提供的操作方法只能传入一个参数执行SQL任务,而我们现在查询某一页的数据,需要知道是第几页和每页多少条数据这两个参数,所以我们需要将这两个参数封装在一个对象里面(或者使用Map)
编写一个类(起名叫查询对象类)来封装这些查询数据

@Setter
@Getter
/**
* 封装分页查询需要的两个请求传入的分页参数
*/
public class QueryObject {
	private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)
	private int pageSize = 3; // 每页显示条数(需要给默认值)
}

再书写持久层DAO接口和实现类

//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);
	}
}

前台分页功能实现

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

  1. 必须先完成业务层组件,保证后台测试通过。
  2. 遵循 MVC 思想。
  3. 浏览器发出分页请求参数(去往第几页/每页多少条数据),在 Servlet 中接收这些参数,并封装
  4. 到 QueryObject 对象,调用 Service 中分页查询方法(query)。
  5. 把得到的分页查询结果对象(PageResult)共享在请求作用域中,跳转到 JSP,显示即可。
  6. 修改 JSP 页面,编写出分页条信息(分页条中的信息来源于 PageResult 对象)。

修改ProductServlet.java和展示jsp

  1. 获取页面请求参数,判断是查询操作,调用查询方法,获取分页参数
  2. 将参数封装成查询对象QueryObject
  3. 调用业务层方法查询某一页数据
  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);
}

修改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>

常见问题

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

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

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

相关文章

HTML+CSS+JS网页设计期末课程大作业 京剧文化水墨风书画

Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业&#xff0c;茶文化网站 | 中华传统文化题材 | 京剧文化水墨风书画 | 中国民间年画文化艺术网站 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在操作…

EasyExcel复杂表头导出(一对多)升级版

一、前言 在之前写的 EasyExcel复杂表头导出&#xff08;一对多&#xff09;的博客的结尾&#xff0c;受限于当时的能力和精力&#xff0c;留下一些问题及展望。现在写下此博客&#xff0c;目的就是解决之前遗留的问题。 背景介绍&#xff0c;见上述链接指向的博客&#xff0c;…

vue3 route和router的区别以及如何传参数接受参数,如何像vue2一样使用$route和$router详解

vue3 route和router的区别以及如何传参数接受参数&#xff0c;如何像vue2一样使用$route和$router详解 因为我们在 setup 里面没有访问 this&#xff0c;所以我们不能再直接访问 this.$router 或 this.$route。作为替代&#xff0c;我们使用 useRouter 和useRoute函数,或者 Vu…

HTML小游戏21 —— html5版暴打皮卡丘游戏(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】本节教程我会带大家使用 HTML…

微信小程序--基础内容(详解)(一)

一、常用标签 1、view 标签 view 标签是一个块级元素&#xff0c;类似于 div&#xff08;小程序里面没有div标签&#xff09;&#xff0c;里面可以放任何内容或者插值表达式&#xff0c;如下所示&#xff1a; <view>这是view标签<view> <view>{{num}}<…

谷歌新版本跨域错误深度剖析与解决:request client is not a secure context and the resource is in more-private address

快速解决&#xff1a; 最近在测试http服务时&#xff0c;谷歌浏览器报了以下错误 “The request client is not a secure context and the resource is in more-private address space ‘local’”. 从报错信息来看&#xff0c;“不安全的请求方请求了更私有的本地资源” 对于…

API接口开发其实特简单,Python Flask Web 框架教程来了

大家好&#xff0c;日常工作中&#xff0c;无论你是数据工程师、数据挖掘工程师&#xff0c;甚至数据分析人员&#xff0c;都不可避免的与他人进行数据交互&#xff0c;API接口提供数据是最常见的形式。 今天我给大家分享 Python Flask Web 框架教程&#xff0c;共计10个部分&…

Vue面试题你知道多少

✅作者简介&#xff1a;大家好我是hacker707,大家可以叫我hacker&#xff0c;新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;带你玩转Vue &#x1f4ac;推荐一款模拟面试、刷题神器&…

前端401错误 解决方法:响应拦截器

目录 1.该问题出现的原因 2.处理401问题的解决方案原理 3.使用响应拦截器解决问题 1.该问题出现的原因 在前后端分离项目中&#xff0c;最常见的是前端点击登录后&#xff0c;后端返回token字符串&#xff0c;这个token可以看作是一个“令牌”&#xff0c;就比如你去酒店办理…

Vue实战【调整Vue-element-admin中的菜单栏,并添加顶部模块菜单栏】

目录&#x1f31f;前言&#x1f31f;小伙伴们先看&#x1f31f;实现思路&#x1f31f;具体代码&#x1f31f;最后&#x1f31f;前言 因为最近在整合公司的项目&#xff0c;需要把所有系统里的功能集成到一个项目里&#xff0c;这样就导致菜单栏目录会特别的多&#xff0c;不便…

【JavaScript】手撕前端面试题:事件委托 | 判断URL是否合法 | 全排列

&#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff08;源创征文一等奖作品&#xff09;&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&#xff09; &#x1f5a5;️ TypeScript知识总结&…

【Axure】Axure RP 9下载、安装、授权、汉化

目录一、Axure RP 9 下载二、Axure RP 9 安装三、Axure RP 9 授权四、Axure RP 9 汉化一、Axure RP 9 下载 1、Axure RP 9 下载地址&#xff1a;https://www.axure.com/release-history/rp9 2、其他版本下载地址 ①登录axure官网:https://www.axure.com/ ②拉到最下面找到相关…

很好看的爱心表白代码(动态)

分享几个好看的爱心表白代码❤️爱心代码❤️&#xff08;C语言&#xff09;❤️流动爱心❤️&#xff08;htmlcssjs&#xff09;❤️线条爱心❤️&#xff08;htmlcssjs&#xff09;❤️biu表白爱心❤️&#xff08;htmlcssjs&#xff09;❤️matlab爱心函数❤️&#xff08;需…

Vue3+TS+Vite 入门指南

最近尝试上手 Vue3TSVite&#xff0c;对比起 Vue2 有些不适应&#xff0c;但还是真香~ 上手前先说下 Vue3 的一些变化吧~ Vue3 的变化 Vue3 带来的变化主要有以下几个方面&#xff1a; 使用层面 对比起 Vue2 启动速度快很多&#xff0c;新项目从 1s 升级到不到 500msvite.co…

Element-UI新手学习记录(一)

Layout 布局 通过基础的 24 分栏&#xff0c;迅速简便地创建布局。 span的作用 一行默认24个span&#xff0c;属性放在el-col中决定此元素占据多少span gutter属性 放在el-row中&#xff0c;给各个块之前设置间隔&#xff0c;但是是割的代码块的宽度。 offset属性 放在el…

小程序页面之间数据传递的四种方法

近期再使用小程序开发的时候遇到小程序页面和页面之间的数据传递问题。总结一下大致有以下几种方式实现页面数据传递。 最常见的就是路由传参&#xff0c;使用场景主要是页面汇总的少量数据的传递。以下都以Tarovue示例&#xff0c;原生、react或者uniapp同理&#xff0c;替换…

Pinia(二)了解和使用Store

Store Store 是保存状态(state)和业务逻辑的实体, store 不应该与我们的组件绑定. 换句话说, store 就是全局状态.store 有三个关键概念, 分别是 state, getters 和 actions, 这与 Vue 组件中的 data, computed 和 methods 是相对应的概念. 定义 store 通过 defineStore 函数…

Vue页面路由参数的传递和获取

文章目录1. 通过动态路由参数传递2. 通过query字符串传递3. props 隐式传递vue 页面路由切换时传参的方式有如下几种&#xff1a; 动态路由参数 它隐藏字段信息&#xff0c;相对于来说较安全&#xff0c;同时地址栏中的地址也相对较短 它必须是先定义后使用&#xff0c;一般用…

关于嵌套使用 iFrame 出现 Refused to display in aframe 拒绝连接访问 和 ‘X-Frame-Options‘ to ‘SAMEORIGIN‘ 的解决方案【已解决】

目录问题描述原因分析问题解决总结今天在迁移旧项目时&#xff0c;出现了如下错误提示&#xff1a; Refused to display in a frame because it set X-Frame-Options to SAMEORIGIN问题描述 当前项目是一个生产环境正常运行的项目&#xff0c;由于我们要迁移服务器并且部署 k…

Pro2:修改div块的颜色

什么是JavaScript&#xff1f;实现目标实现代码实现效果实现方法&#x1f49b;作者主页&#xff1a;静Yu &#x1f9e1;简介&#xff1a;CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家&#xff0c;前端知识交流社区创建者 &#x1f49b;社区地址&#xff1a;前端知识交…