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>

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

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

相关文章

字节跳动 (提前批-算法工程师-电商业务) 一面面经

文章目录 面试情况1、对简历项目提问&#xff1a;1.1、介绍项目中的xx分类、xx概念分类、xx概念归一化&#xff0c;具体做法&#xff0c;为什么这么做&#xff1f;1.2、标注问题&#xff0c;如何标注&#xff1f;1.3、如何设计prompt让chatgpt得到高质量标注&#xff1f;1.4、类…

perl:用 Net::Server 创建简单的流媒体服务器来播放.flv文件

这是一个使用Perl Net::Server 模块创建的简单流媒体服务器示例&#xff0c;它能够播放.flv文件。 首先&#xff0c;确保安装了Net::Server模块&#xff0c;如果没有安装&#xff0c;可以使用CPAN来安装它&#xff1a; 运行 cpan Net::Server RHANDOM/Net-Server-2.014.tar.…

Spring框架常见注解(Spring,SpringMvc,SpringBoot)

Spring常见注解 Component、Controller、Service、Repository 使用在类上用于实例化Bean Autowired 使用在字段上用于根据类型依赖注入 Qualifier 结合Autowired一起使用用于根据名称进行依赖注入 Scope 标注Bean的作用范围 Configuration 指定当前类是一个 Spring 配…

HTML公式查询网

闲着无聊做了一个公式查询网&#xff0c;核心思路主要就是把数据库里面的内容找出来。比较低级。 <DOCTYPE !html> <html> <head><meta charset"utf-8"><title>公式查询网</title><style>* {margin: 0;padding: 0;box-si…

centos中使用Docker安装rabbitmq记录

一、安装rabbitmq docker run -d --name rabbitmq -p 5672:5672 -p15672:15672 -v rabbitmq-plugin:/plugins -e RABBITMQ_DEFAULT_USERxiaoqi -eRABBITMQ_DEFAULT_PASS123456 rabbitmq:latest二、配置web管理界面 # 查看运行的容器 docker ps -a # 根据容器id进入容器内部 …

YoloV1模型

You Only Look Once 文章目录 You Only Look Once置信度定义类别条件概率NMSnp.maxmiumnp.argsort() Yolov1直接采用网络特征输出&#xff0c;实现置信度预测、分类、边界框回归&#xff1b; 核心内容总结&#xff1a; 输入图像划分为 S S 网格。如果对象的中心落入网格单元中…

Leetcode 3163. String Compression III

Leetcode 3163. String Compression III 1. 解题思路2. 代码实现 题目链接&#xff1a;3163. String Compression III 1. 解题思路 这一题的话就是一个简单的贪婪算法&#xff0c;把相同的字符进行归并&#xff0c;然后按照题目中的表示方法进行表示一下即可。 2. 代码实现…

linux 安装chrome浏览器

一、下载安装包 下载地址&#xff1a;https://download.csdn.net/download/k0307x1990y/89349171 二、安装流程 [rootlocalhost ~]# rpm -ivh *.rpm [rootlocalhost ~]# yum -y localinstall google-chrome-stable_current_x86_64.rpm [rootlocalhost ~]# 三、修改配置文件…

Java对象头你不知道的地方

在Java中&#xff0c;每个对象都拥有一个对象头&#xff0c;这些对象头包含了关于对象的一些元数据信息。对象头(Header)包含2部分&#xff08;若为数组&#xff0c;则包含3部分&#xff09;&#xff1a; 一、第一部分为Mark Word&#xff0c;用于存储对象自身的运行时数据&am…

Vxe UI 表单设计器、零代码平台

vxe-pc-ui Vxe UI 表单设计器、零代码表单设计器 安装 Vxe UI PC端组件库 官方文档 查看 github、gitee // ...import VxeUI from vxe-pc-uiimport vxe-pc-ui/lib/style.css// ...// ...createApp(App).use(VxeUI).mount(#app)// ...使用 vxe-form-design 设计器组件 vxe-fo…

【安装笔记-20240523-Windows-安装测试 ShareX】

安装笔记-系列文章目录 安装笔记-20240523-Windows-安装测试 ShareX 文章目录 安装笔记-系列文章目录安装笔记-20240523-Windows-安装测试 ShareX 前言一、软件介绍名称&#xff1a;ShareX主页官方介绍 二、安装步骤测试版本&#xff1a;16.1.0下载链接功能界面 三、应用场景屏…

QML的Image 路径问题(source)

四种路径格式 在 QML 中&#xff0c;当你使用 Image 元素的 source 属性来指定一个图片的路径时&#xff0c;有几种不同的方式可以指定这个路径&#xff0c;每种方式都有其特定的用途和上下文。 相对路径&#xff1a; QML 文件和一个名为 close.png 的图片在同一目录下&#x…

Spring:面向切面(AOP)

1. 代理模式 二十三种设计模式中的一种&#xff0c;属于结构型模式。它的作用就是通过提供一个代理类&#xff0c;让我们在调用目标方法的时候&#xff0c;不再是直接对目标方法进行调用&#xff0c;而是通过代理类**间接**调用。让不属于目标方法核心逻辑的代码从目标方法中剥…

【热门话题】Debian常用命令指南

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Debian常用命令指南引言1. 文件与目录操作lscdmkdirrmcpmv 2. 包管理aptdpkg 3.…

【k8s】 busybox镜像、挂载volume卷

1. 概述 busybox是一个包含了nslookup,ping,wget等网络处理命令的Pod容器&#xff08;不含curl命令&#xff09;&#xff0c;它的体积非常小&#xff0c;适合做一些容器内的网络调试。 即创建一个docker &#xff0c;进去执行 ping 命令等 2. 启动容器 2.1 会自动退出&…

minaActivatorA12+物主锁完美解信号,可登iCloud,有消息通知,支持iOS17.5.1+

原创 IOS福利部落 IOS福利部落 2024-05-26 19:35 福建 Mina Activator A12是一款绕过物主锁界面的解锁工具&#xff0c;可以激活所有iPhone恢复信号&#xff0c;并且支持插卡接打电话、收发短信、4G流量上网&#xff0c;支持iCloud登录&#xff0c;有消息通知&#xff0c;支持i…

sklearn实现线性回归

sklearn实现线性回归 一、数据集介绍二、使用sklearn实现线性回归一、数据集介绍 本案例使用女性身高体重数据集,数据集如下图所示: 可以看到,数据集有15行2列。 二、使用sklearn实现线性回归 sklearn中的线性模型模块是linear_model。这里使用linear_model下的普通线性…

【Linux】-Redis安装部署[15]

目录 简介 安装 1、配置EPEL仓库 2、安装redis 3、启动redis 4、放行防火墙&#xff0c;redis使用端口6379 5、进入redis服务 简介 redis是一个开源、使用C语言编写的、支持网络互交的、可基于内存也可持久化的Key-Value数据库。redis的特点就是&#xff1a;快&#xf…