• JAVA-分页查询


    分页查询

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

    真假分页

    假分页: 其原理还是将所有的数据读到内存中,翻页从内存中读取数据, 优点: 实现简单,性能高 缺点:如果数据大容易造成内存溢出
    真分页: 每次翻页从数据库查询数据(即磁盘) , 优点 : 不容易造成内存溢出 缺点: 实现复杂,性能相对低一些

    分页效果

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

    分页需要传递的参数

    需要用户传入的参数:
    currentPage: 当前页,跳转到第几页, 第一次访问,我们创建一个对象,默认值是1
    pageSize: 每页显示多少行数据, 第一次我们也给个默认值 比如10条

    分页需要展示的数据

    1. 当前页的货品信息
    2. 首页是第几页
    3. 上一页是第几页
    4. 下一页是第几页
    5. 一共有多少页,和末页的值是一样的
    6. 数据一共有多少条(行)
    7. 当前是第几页
    8. 每页显示多少条信息

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

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

    书写从数据库查询的sql语句

    第一条sql 查询数据库中有多少条数据,COUNT后面不能有空格

    SELECT COUNT(*) FROM 表名
    
    • 1

    第二条sql 根据传入的参数查询第几页,一页多少条数据的结果集

    # 第一个 ?:从哪一个索引的数据开始查询(默认从 0 开始)
    # 第二个 ?:查询多少条数据
    SELECT * FROM 表名 LIMIT ?, ?
    
    • 1
    • 2
    • 3

    接下来分析第二条 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分页查询实现

    访问流程:在这里插入图片描述

    封装需要展示的数据

    如果不封装数据,每个数据都需要存到作用域中,数据太分散,不方便统一管理

    /**
    * 封装结果数据(某一页的数据)
    */
    @Getter
    public class PageResult {
    	// 两个用户的输入
    	private int currentPage; // 当前页码
    	private int pageSize; // 每页显示的条数
    	// 两条 SQL 语句执行的结果
    	private int totalCount; // 总条数
    	private List data; // 当前页结果集数据
    	// 三个程序计算的数据
    	private int prevPage; // 上一页页码
    	private int nextPage; // 下一页页码
    	private int totalPage; // 总页数/末页页码
    	// 分页数据通过下面构造期封装好
    	public PageResult(int currentPage, int pageSize, int totalCount, List
    	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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    持久层DAO

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

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

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

    //DAO接口提供两个根据查询对象的查询方法
    int queryForCount();
    List 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 queryForList(QueryObject qo) {
    	SqlSession session = MyBatisUtil.getSession();
    	List products =
    	session.selectList("cn.xxx.mapper.ProductMapper.queryForList",qo);
    	session.close();
    	return products;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    修改productMapper.xml

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    修改QueryObject.java

    给这个类增加getStart方法,返回根据当前页,每页大小需要从数据库从第几行开始显示

    @Setter
    @Getter
    /**
    * 封装分页查询需要的两个请求传入的分页参数
    */
    public class QueryObject {
    	private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)
    	private int pageSize = 3; // 每页显示条数(需要给默认值)
    	// 用于 Limit 子句第一个 ? 取值
    	public int getStart(){
    		return (currentPage - 1) * pageSize;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    业务层ProductService

    调用持久层DAO完成数据的查询,并将多个数据封装到一个对象中

    //IProductService接口
    public interface IProductService {
    	/**
    	* 完成查询某一页的业务逻辑功能
    	*/
    	PageResult query(QueryObject qo);
    }
    //Service实现类
    public class ProductServiceImpl implements IProductService {
    	private IProductDAO productDAO = new ProductDAOImpl();
    	@Override
    	public PageResult query(QueryObject qo) {
    		// 调用 DAO 查询数据数量
    		int totalCount = productDAO.queryForCount();
    		// 为了性能加入判断,若查询的数据数量为 0,说明没有数据,返回返回空集合,即集合中没有
    		元素
    		if(totalCount == 0){
    			return new PageResult(qo.getCurrentPage(), qo.getPageSize(),
    			totalCount, Collections.emptyList());
    		}
    		// 执行到这里代表有数据,查询当前页的结果数据
    		List products = productDAO.queryForList(qo);
    		return new PageResult(qo.getCurrentPage(), qo.getPageSize(), totalCount,
    		products);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    前台分页功能实现

    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 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" %>
    
    	
    		产品列表
    		
    	
    	
    		
    添加
    编号 货品名 分类编号 零售价 供应商 品牌 折扣 进货价 操作
    ${status.count} ${product.productName} ${product.dir_id} ${product.salePrice} ${product.supplier} ${product.brand} ${product.cutoff} ${product.costPrice} 删除 修改
    首页 上一页 下一页 尾页 当前第 ${pageResult.currentPage} / ${pageResult.totalPage} 页 一共 ${pageResult.totalCount} 条数据 跳转到 条数据
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    常见问题

    若开始翻页操作成功,翻了几页不能翻了,只能重启tomcat才能翻,问题: DAO中没有关闭SqlSession对象

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    【数据结构】栈和队列
    举例说明计算机视觉(CV)技术的优势和挑战
    OCR之CRNN模型简单理解
    Allure精通指南(02)Mac和Windows系统环境配置
    iOS UIKit
    Unity中的MVC思想
    Kotlin第五弹:数据容器
    【MySQL基础】一条查询和更新语句的执行流程01-02
    基于Matlab创建跟踪场景、模拟目标运动和模拟雷达检测仿真(附源码)
    【Linux】kubernetes - kubectl
  • 原文地址:https://blog.csdn.net/m0_54883970/article/details/126105012