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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux-部分:实用指令

1 指定运行级别 1&#xff09;基本介绍&#xff1a; 运行级别说明&#xff1a; 0&#xff1a;关机1&#xff1a;单用户【找回丢失密码】2&#xff1a;多用户状态没有网络服务3&#xff1a;多用户状态有网络服务4&#xff1a;系统未使用保留给用户5&#xff1a;图形界面6&…

新业务 新市场 | 灵途科技新品亮相马来西亚亚洲防务展

5月6日&#xff0c;灵途科技携新品模组与武汉长盈通光电&#xff08;股票代码&#xff1a;688143&#xff09;携手参加第18届马来西亚亚洲防务展。首次亮相海外&#xff0c;灵途科技便收获全球客户的广泛关注&#xff0c;为公司海外市场开拓打下坚实基础。 灵途科技与长盈通共同…

基于Llama 3搭建中文版(Llama3-Chinese-Chat)大模型对话聊天机器人

前面两篇博文&#xff0c;我们分别在个人笔记本电脑部署了Llama 3 8B参数大模型&#xff0c;并使用Ollama搭建了基于 Web 可视化对话聊天机器人&#xff0c;可以在自己电脑上愉快的与Llama大模型 Web 机器人对话聊天了。但在使用过程中&#xff0c;笔者发现Llama大模型经常出现…

避免锁表:为Update语句中的Where条件添加索引字段

最近在灰度环境中遇到一个问题&#xff1a;某项业务在创建数据时耗时异常长&#xff0c;但同样的代码在预发环境中并未出现此问题。起初我们以为是调用第三方接口导致的性能问题&#xff0c;但通过日志分析发现第三方接口的响应时间正常。最终&#xff0c;我们发现工单表的数据…

【C++】C++11(一)

C11是一次里程碑式的更新&#xff0c;我们一起来看一看~ 目录 列表初始化&#xff1a;{ }初始化&#xff1a;std::initializer_list&#xff1a; 声明&#xff1a;auto&#xff1a;decltype&#xff1a; STL的一些变化&#xff1a; 列表初始化&#xff1a; { }初始化&#xf…

音视频开发4-补充 FFmpeg 开发环境搭建 -- 在windows 上重新build ffmpeg

本节的目的是在windows 上 编译 ffmpeg 源码&#xff0c;这样做的目的是&#xff1a;在工作中可以根据工作的实际内容裁剪 ffmpeg&#xff0c;或者改动 ffmpeg 的源码。 第一步 &#xff1a;下载&#xff0c; 安装&#xff0c;配置 &#xff0c;运行 msys64 下载 下载地址&…

如何使用ssh将vscode 连接到服务器上,手把手指导

一、背景 我们在开发时&#xff0c;经常是window上安装一个vscode编辑器&#xff0c;去连接一个虚拟机上的linux&#xff0c;这里常用的是SSH协议&#xff0c;了解其中的操作非常必要。 二、SSH协议 SSH&#xff08;Secure Shell&#xff09;是一种安全协议&#xff0c;用于…

某某某加固系统分析

某某某加固系统内核so dump和修复&#xff1a; 某某某加固系统采取了内外两层native代码模式&#xff0c;外层主要为了保护内层核心代码&#xff0c;从分析来看外层模块主要用来反调试&#xff0c;释放内层模块&#xff0c;维护内存模块的某些运行环境达到防止分离内外模块&am…

vulnhub靶机De-ICE_S2.100_(de-ice.net-2.100-1.0)

下载地址&#xff1a;https://download.vulnhub.com/deice/De-ICE_S2.100_%28de-ice.net-2.100-1.0%29.iso 靶机搭建 注意下载下来的是iso文件接下来说明系统选择 linux的Debian 7.x就可以 然后注意一点我们需要创建一个192.168.2.0/24的网卡进行连接&#xff08;靶机ip地址…

RTOS(3)极简ARM架构与汇编

1.掌握八条汇编指令即可 读内存loadLDR R0&#xff0c;[addrA]写内存storeSTR R0&#xff0c;[addrA]加ADD R0&#xff0c;R1&#xff0c;R2减SUB R0&#xff0c;R1&#xff0c;R2比较CMP R0&#xff0c;R1跳转B / BL入栈PUSH { R3&#xff0c;LR }出…

OpenStack平台Glance管理

1. 规划节点 使用OpenStack平台节点规划。 IP主机名节点192.168.100.10controller控制节点192.168.100.20compute计算节点 2. 基础准备 使用实战案例-部署的OpenStack平台。 IP 主机名 节点 192.168.100.10 controller 控制节点 192.168.100.20 copute 计算节点 02 案例分…

基于机器学习判断面部微表情发现哪些人更容易诊有帕金森病

1. 概述 帕金森病&#xff08;Parkinson’s disease&#xff0c;PD&#xff09;是一种慢性、进展性的神经退行性疾病&#xff0c;主要影响运动系统。该病症以大脑中黑质致密部多巴胺能神经元的逐渐丧失为特征&#xff0c;导致多巴胺&#xff08;一种重要的神经递质&#xff09…

门禁-jenkins的构建状态同步到gitlab提交流水线

API接口文档 https://docs.gitlab.cn/jh/api/commits.html 配置pipline流水线 生成http请求代码&#xff1a; 使用HttpRequest插件生成 - sharelibs内容 //这是share libs里的 package devopsdef httpReq(reqType, reqUrl, reqBody, accessToken){def gitServer "…

Radware Alteon负载均衡-配置证书组

证书组&#xff1a;可以使用证书组将多个服务器证书与虚拟服务相关联。这提供了对服务器名称指示(Server Namelndication&#xff0c;SNI)的支持&#xff0c;允许在相同的IP和端口后面托管多个主机名。使用SNI&#xff0c;浏览器发送请求的主机名&#xff0c;使服务器能够在进行…

滤波电路应用笔记

滤波器 什么是滤波器&#xff1f; 滤波器是一种使某些频率或频带上的电信号通过而阻止其他信号通过的装置。 滤波电路的作用是尽可能减少脉动直流电压中的交流分量&#xff0c;保持其直流分量&#xff0c;降低输出电压的纹波系数&#xff0c;并使波形相对平滑。整流电路的输出…

以前:不会用电脑;现在:不会用AI

购买特价商务机票需要一些策略和灵活性。、 提前规划&#xff1a;商务舱票价通常在出发日期的2-3个月前最便宜。尽早规划您的行程并开始关注票价。 使用比价工具&#xff1a;使用Skyscanner、Kayak等比价网站来比较不同航空公司的商务舱票价。这些网站可以显示多个航空公司的价…

grpc、多集群、多租户

gRPC和服务发现 一个A high-performance, open-source universal RPC framework&#xff0c;高性能、开源的通用 RPC 框架。使用protobuf 语言基于文件定义服务&#xff0c;通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub。移动端上面则是基于标准的 HTTP…

使用Java 将字节数组转成16进制的形式

概述 在很多场景下&#xff0c;需要进行分析字节数据&#xff0c;但是我们存起来的字节数据一般都是二进制的&#xff0c;这时候就需要我们将其转成16进制的方式方便分析。比如在做音视频的时候&#xff0c;需要看下我们传输的视频h264数据中是否有对应的I帧或者B帧等数据&…

01JAVA基础

目录 1.基础语法 1.1 注释 1.2 关键字 1.3 常量 1.4 数据类型 1.5 变量 1.6 标识符 1.7 类型转换 2.算数运算符和分支语句 2.1 算数运算符 1.常规运算符 2.赋值运算符 3.自增自减 4.关系运算符 5.逻辑运算符 6.三元运算符 2.2 数据输入(Scanner) 2.3 分支判断…