PageHelper分页

2024-05-27 00:36
文章标签 分页 pagehelper

本文主要是介绍PageHelper分页,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • PageHelper分页
    • ThreadLocalMap和ThreadLocal
    • 执行完PageHelper.startPage之后,分页参数存储到哪里了?
    • Page和List的关系?
    • PageInterceptor分页拦截器的作用?
    • PageInfo的作用与结构?
    • 最后看下引入的pagehelper分页依赖坐标与mybatis坐标

PageHelper分页

PageHelper可以帮助我们后端数据分页,具体的使用场景如下图:
在这里插入图片描述
那么它的原理是什么呢?在讲述它的原理之间我们先来说下ThreadLocal和ThreadLocalMap的作用。

ThreadLocalMap和ThreadLocal

每一个线程都有一个ThreadLocalMap集合,这个集合的key是ThreadLocal,这个集合的value是我们要存储的某个值。
所以一个线程里面其实会牵涉到多个ThreadLocal对象。

为什么一个线程需要设置一个专属的ThreadLocalMap呢?因为避免当前线程的数据被污染,比如说当A线程使用PageHelper.startPage(1,6)方法进行分页查询的时候,当执行完这句代码之后就会把分页参数设置到ThreadLocalMap里面,比如我现在的分页参数是查询当前页pageNum为1的数据,然后每页的数据大小pageSize为6,其实也就是查询数据库表的前六条数据。那这个时候我们就需要把pageNum和pageSize这两个关键的参数设置到ThreadLocalMap保存。那么问题来了,假如这个时候别的地方的线程也调用了PageHelper.startPage方法去设置参数,这不就冲突了吗?
因此 每个线程我们都会设置一个私有数据存储的地方,这个私有区域只有当前线程才能访问,其他线程不能访问。我们每个线程的私有区域其实就是ThreadLocalMap。

那么问题又来了,既然都已经有了线程私有区域ThreadLocalMap了,为什么我们还需要设置多个ThreadLocal作为key呢?原因很简单,因为一个线程里面可以操作多个客户端,比如在netty模型里面,一个线程就可以处理多个客户端连接,假如这多个客户端都需要分页的话,那么我们需要把分页设置数据pageNum和pageSize存储到那个地方呢?这些客户端存储的数据怎么区分呢?答案就是使用ThreadLocal进行区分,所以你可以把一个ThreadLocal理解成当前线程处理的一个客户端,然后value数据就是当前线程为当前客户端保存的私有线程数据。

那么这样的话,我们分页的时候,就可以通过ThreadLocal为每个客户端保存它专属的分页设置数据了,所有的线程互不影响,并且一个线程里面的所有的客户端也互不影响。

在这里插入图片描述
可以发现每个线程都有一个ThreadLocalMap私有数据存储空间。里面的key是ThreadLocal类型,value就是具体的存储的数据。

执行完PageHelper.startPage之后,分页参数存储到哪里了?

分页参数存储到了PageHelper的父类PageMethod的ThreadLocal属性中了如下图:
在这里插入图片描述
在这里插入图片描述
存储到了PageMethod的ThreadLocal中,每个客户端对应一个ThreadLocal私有区域,里面存储的是Page分页相关信息,接下来看一下Page分页信息都有什么,如下图:
在这里插入图片描述
最常见的就是当前页数,每页大小,总数据条数,以及总页数等。

Page和List的关系?

Page是保存分页数据信息的。Page是List的一个子类,如下图:
在这里插入图片描述

PageInterceptor分页拦截器的作用?

PageHelper内部实现了一个名为PageInterceptor的拦截器,该拦截器会被MyBatis加载到拦截器链中。当MyBatis执行查询操作的时候,PageInterceptor会在真正执行查询sql语句之前,拦截sql语句,为什么呢?因为PageHelper需要去进行分页查询,而分页查询则必须去修改原先的sql查询语句,比如说拦截到sql查询语句之后,我们会去修改这个sql语句,跟句我们ThreadLocal里面之前获取的Page分页参数,去改造查询sql语句,比如说加一个limit关键字,进行适当的查询,生成最新的sql,然后去执行这个sql语句。
这样其实也就实现了我们的分页查询。

在这里插入图片描述
在执行UserMapper.selectAll相关的sql查询之前,PageInteceptor分页拦截器会拦截sql语句并进行修改。

不知道你有没有想一个问题,就是在下一句代码执行的时候,也就是new PageInfo执行的时候,它要求参数必须是Page类型才可以进行数据设置,但是我们的userList分明是个List集合啊!那么问题来了,为什么list集合在后面变成了Page类型呢?我们代码里面也没有手动的转换啊?这是怎么回事呢?其实是因为当我们的PageInteceptor分页插件拦截查询sql语句之后,修改sql语句,然后执行sql语句获取执行数据集合的时候,得到的集合其实是Page类型,然后PageInteceptor分页插件再把这个Page子类型向上转型为它的父类List类型。因此我们得到的userList集合类型是可以向下转型为Page类型的,它实际上是一个Page类型。

那么还有一个问题,为什么我们的PageInfo可以通过userList得到所有的数据条数,比如我们数据库表总数据是11条,但我们每页大小是6条,现在分页之后,我们取出第一页数据,那么在userList其实我们查询出来的数据只有前六条而已,那么为什么在使用PageInfo的构造函数之后,参数是userList,但是我们却可以得到总数据条数是11条呢?
其实这也是PageInteceptor分页插件的功劳,因为我们知道改造sql语句之前的sql是什么样子的,没有改造之前查询的就是总数据条数,我们可以在PageInteceptor分页拦截器拦截的时候获取总数据条数,然后设置给Page,最后Page转换为list。然后在PageInfo中list又会向下转型为Page,我们也就在PageInfo中得到总数据条数了。

注意如果要想PageInterceptor分页拦截器生效,那么必须需要在mybatis配置文件中声明使用PageInterceptor插件,如下图:
在这里插入图片描述
不然的话此分页插件失效,那么我们的整体的分页查询也就会失败了。

PageInfo的作用与结构?

首先说下PageInfo的作用?PageInfo是最终取分页数据的对象,比方说我们的分页查询的数据集合,当前页,每页大小,总数据条数,上一页是多少页,下一页是多少页等,我们程序员都是从PageInfo里面读取的。但是有人可能会有疑问,这些东西Page对象里面基本上也有啊,为什么不从Page对象里面读取呢?因为Page对象是面向源码的,源码读取数据的时候确实是从Page对象里面,比如PageInterceptor分页插件存储数据的时候就会用到Page对象。
但我们最终自己数据读取的时候是从PageInfo里面读取的,如下图:
在这里插入图片描述

接下来看下PageInfo对象的结构,如下图:
在这里插入图片描述
除了一些基本的分页数据,可以发现PageInfo类还继承了PageSerializable类,这个类里面主要是存储我们的分页数据list集合和查询总数据total的,如下图:
在这里插入图片描述

最后看下引入的pagehelper分页依赖坐标与mybatis坐标

在这里插入图片描述

 <dependencies><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version></dependency><!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>6.1.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.10</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency></dependencies>

这篇关于PageHelper分页的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1006027

相关文章

oracle分页和mysql分页

mysql 分页 --查前5 数据select * from table_name limit 0,5 select * from table_name limit 5 --limit关键字的用法:LIMIT [offset,] rows--offset指定要返回的第一行的偏移量,rows第二个指定返回行的最大数目。初始行的偏移量是0(不是1)。   oracle 分页 --查前1-9

fastreport打印trichedit分页问题的解决

用fastreport来打印richedit里面的内容。刚开始放一个frxrichview组件到报表上,然后在 var str: TMemoryStream; begin    begin      str:= TMemoryStream.Create;      CurrRichRecord.richedit.Lines.SaveToStream(str);      str.Posit

简单Hbase 分页方案

简单Hbase分页方案 网上大多数分页方案分为从服务端分页或者从客户端分页 服务端分页方式主要利用PageFilter过滤器,首先太复杂,其次针对集群的兼容性不是很好,作者利用服务端分页+客户端分页结合方式给出一种简单易行的中间方案。 1.利用PageFilter过滤器从服务端分页,过滤出所需要的最大条数, 注:作者认为大多数用户不会进行太深的翻页,假设pageSize=5,客户饭100页一共

SpringBoot项目-实现简单的CRUD功能和分页查询

背景 本博文主要是创建了一个新的SpringBoot项目,实现基本的增删改查,分页查询,带条件的分页查询功能。是方便初学者学习后端项目的一个比较清晰明了的实践代码,读者可根据博文,从自己动手创建一个新的SpringBoot项目,到使用PostMan测试基本请求,完完全全实践一遍,写出自己的代码,或者实现自己想要的功能。因为在这个过程中会遇到许多的问题,从JDK的版本选择到跑通SpringBo

Jasperreports+jaspersoft studio学习教程(八)- 报表分页和大量数据内存处理

9.1 设计报表模板 9.1.1 使用Table组件新建模板(步骤参考教程七)如下: 9.1.2 模板自带变量 $V{PAGE_NUMBER} :代表当前页数(可以是页码也可以是页数,通过TextField的计算时间的不同值来设置) $V{PAGE_COUNT} :当前页面中记录的数目 $V{groupname_COUNT} :   代表当前组的记录数 $V{COLUMN_NU

操作系统分页式存储管理

每次输入地址后,计算出页号,若页号越界,则给出错误提示。否则依次调用FIFO和LRU算法,这里值得注意的是,由于我们的FIFO算法先于LRU算法被调用,那么当在处理FIFO算法时,我们暂且不将位视图相应位置做变化,留到处理LRU算法再做处理。 对于FIFO、LRU算法的缺页,我们分两种情况考虑,第一种是模拟栈内还有空间,那么直接将其入栈。第二种是模拟栈内无空间,要发生置换。发生置换时把模拟栈最底

PHP 分页实现序号递加或递减排序

PHP 分页实现序号递加或递减排序 实现思路: 在循环前赋值变量i,然后在循环输出变量i 。 实现序号递加1表达式:i=(页数-1)× 每页条数+1                循环:$i++               asp:i=i+1 实现序号递减1表达式:i=总数—(页数-1)× 每页条数 +1           循环:$i--             asp:i=i-1

【硬刚ES】ES入门 (13)Java API 操作(4)DQL(1) 请求体查询/term 查询,查询条件为关键字/分页查询/数据排序/过滤字段/Bool 查询/范围查询/模糊查询/高亮查询/聚合查

本文是对《【硬刚大数据之学习路线篇】从零到大数据专家的学习指南(全面升级版)》的ES部分补充。 1 请求体查询 2 高亮查询 3 聚合查询 package com.atguigu.es.test;import org.apache.http.HttpHost;import org.apache.lucene.search.TotalHits;import org.elasticse

Oracle、MySQL和SqlServe三种数据库分页查询语句的区别介绍

先来定义分页语句将要用到的几个参数: int currentPage ; //当前页 int pageRecord ; //每页显示记录数 以之前的ADDRESSBOOK数据表为例(每页显示10条记录): 一、SqlServer下载 分页语句 String sql = "select top "+pageRecord +" * from addressbook where id not i

Orderby limit offset分页

SELECT * FROM table_name WHERE some_column = #{value} ORDER BY id LIMIT #{limit} OFFSET #{offset} // 假设你已经配置了 SqlSession try (SqlSession session = sqlSessionFactory.openSession()) { // 调用 countTotal