mybatis源码(五)springboot pagehelper实现查询分页

1、背景

springboot的pagehelper插件能够实现对mybatis查询的分页管理,而且在使用时只需要提前声明即可,不需要修改已有的查询语句。使用如下:

之前对这个功能一直很感兴趣,但是一直没完整看过,今天准备详细梳理下。按照个人的习惯,我喜欢带着问题去看源码,这次浏览源码我希望可以了解以下两个问题:
1)分页插件什么时候被加载的
2)分页插件什么时候生效的,如何生效的

2、技巧(可跳过)

mybatis自身的功能原理这里我们不深入探讨,网上文章很多,我之前也写过类似的文章,这里为了防止文章杂乱,我们只关注感兴趣的点,即mybatis pagehelper分页原理,其它的一笔带过。另外因为mybatis查询生效都是用的代理对象。如果对源码不是很熟悉,很难第一时间找到打断点的位置。不过通过查看page的源码可以知道,最后的分页参数都放到了threadlocal对象里,如下:




而最后使用该threadlocal时是一定会调用它的获取和移除方法,因此我们在它的这两个方法中加断点。等进入断点后再通过方法栈追踪其全流程。如下:

3、源码追踪流程

有了上述方法栈的查看,我们知道了查询的入口和大体流程,现在重新执行查询跟随源码脚步来详细看下分页的实现逻辑。首先是在代码中我们主动进行分页查询,如下:

前三行代码很简单,主要是从httpservletrequest中获取分页参数,并设置到当前线程的threadlocal变量中。第四行则是调用接口方法进行查询。在mybatis中,接口方法最终功能的实现主要是依靠MapperProxy代理类实现(代理类中包含接口和xml配置相关信息),所以接下来我们直接到MapperProxy中打断点追踪(至于mybatis如何关联接口和mapper.xml文件,MapperProxy如何生成等问题不是本文讨论重点,感兴趣的可以单独去查阅或者浏览我以前的相关文章)。

MapperProxy是代理对象,主要调用方法是invoke方法,所以在该方法中加断点,或者依靠第二步中的技巧查看整个查询的方法栈,随后再在MapperProxy对应的行中加断点。具体断点信息如下:

因为method不是Object类型,所以执行else里面的代码:

可以看到最后会执行PlainMethodInvoker对象里的invoke方法,所以我们接着到该方法中打断点并继续追踪查看:

可以看到调用SqlSessionTemplate对象的selectList方法,我们接着向下看:

再接着到DefaultSqlSession中继续查看:

可以看到,最后会调用CachingExecutor的query方法,但是这里要留意一点,那就是CachingExecutor是一个代理对象,执行代理对象方法首先要进入代理,并执行invoke方法。我们这里通过断点调试的步入查看执行哪个类的invoke方法:

可以看到最终是通过Plugin代理实现CachingExecutor对象query方法的调用。我们再接着向下看:

因为要执行的方法是查询方法,其是分页拦截器指定要拦截的方法类型,所以会进入拦截方法中。这里我标记了两个框,第一个是拦截,第二个是不进行拦截直接执行查询方法,因此可以推测分页逻辑是再拦截器中进行的。拦截器中会进行sql的改写,所以这里进入拦截器中进一步查看。拦截器对象为PageInterceptor到这终于和本文的主题关联上了,接下来我们到分页拦截器中看一下:

可以看到源码中都加好注释了,看起来就更简单了,这里我们看下进入分页的条件:

可以看到最后获取的page对象实际上就是我们一开在代码中传入分页参数创建的page对象。因为page对象不为空,所以会返回false,进而不跳过分页逻辑。(另外这里要提醒下各位小伙伴,page对象继承了ArrayList,所以断点查看时看不得page里面的内容,只能看到其size为0。)

我们接着回到主流程向下看,随后会判断是否需要计算总数,默认创建page时需要计算总数,这里我们就不进入before方法查看了,里面逻辑比较简单。下面我们简单看下计算总数的逻辑:

可以看到其计算总数的sql比较精简,主要是根据查询的对象和条件直接计算总数。这里sql的解析和生成主要是依赖jsqlparser工具类实现(jsqlparser的使用可以参考我以前的文章),sql解析比较复杂,感兴趣的可以自行查看。接着我们再回到主流程,看下何时添加的分页查询参数:

可以看到最后再sql末尾加了limit分页参数,而这个sql的改写过程与计算count类似,都是通过jsqlparser工具实现的。

通过上面的流程,我们已经知道了分页插件如何生效的了。但是还有一个问题是分页插件如何被加载的。这个流程比较简单,我也是通过第二步的技巧逆推的全流程。下面我按照正常项目的加载顺利简单介绍下:
当我们在pom中引入pageHelper插件依赖并且在yml中配置分页相关的信息时,项目启动后就会主动的进行插件的初始化并注入到插件拦截器链里面。大体逻辑如下:

可以看到分页插件有个配置类,其在项目初始化的时候会创建分页拦截器,并调用Configuration进行添加,接着我们看下最后会将拦截器添加到哪里:

可以看到最终会添加到拦截器链对象的私有集合里。但是我们最终使用拦截器是在Plugin对象里用的,而不是在拦截器链里面,那Plugin如何使用到该拦截器的呢?

拦截器链里有个pluginAll方法,它会封装拦截器成一个“链式”动态代理对象,代理类是Plugin,该方法会在创建Executor时执行(还记得前面源码里介绍这块的提醒吧,Executor是一个被动态代理的对象),通过pluginAll方法,将拦截器封装成链并将Executor放在链路最后一层

可以看到通过pluginAll方法将拦截器封装成了一个链,下面再看一下Executor的创建就完全清晰了:

至此,我们两个问题都再浏览源码的过程中清晰了。

4、总结

1)该文章主要是探究sringboot分页插件实现的原理,所以对于mapper.xml与接口方法的整合和mybatis代理对象如何实现查看没有细讲,但是这部分也是查询过程中核心的代码。

2)由PageInterceptor分页拦截器拦截指定的查询请求,然后在拦截方法中调用PageHelper中的方法对sql进行改写,最后再进行提交。

2)无论计算总数还是重写分页sql,都是通过jsqlparser工具实现的(为了使得文章主题清晰,这里没有介绍sql的改写过程,jsqlparser的使用可以浏览我以前的文章)

3)Plugin是一个链式动态代理对象,最后一个节点是Executor被代理对象,前面的节点是Interceptor被代理对象。

4)再Plugin.wrap方法中会提取出拦截器里的signature标签,并保存在每个Plugin链式代理对象中。在被代理对象执行对应方法时,如果plugin代理对象包含对应的signature集合则说明当前被代理对象是拦截器,如果不包含signature或者signature标签没有拦截当前方法,则直接执行当前方法。

参考文章:

5分钟!彻底搞懂MyBatis插件+PageHelper原理 - 知乎

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

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

相关文章

大数据湖项目建设方案:文档全文101页,附下载

关键词:大数据解决方案,数据湖解决方案,数据治理解决方案,数据中台解决方案 一、大数据湖建设思路 1、明确目标和定位:明确大数据湖的目标和定位是整个项目的基础,这可以帮助我们确定项目的内容、规模、所…

C语言--每日选择题--Day32

如果大家对读研究生和就业不知道如何抉择,我的建议是看大家的经济基础,如果家里不是很需要你们工作,就读研提升自己的学历,反之就就业;毕竟经济基础决定上层建筑; 第一题 1. 下面代码的结果是:…

springsecurity的NullPointerException产生

springsecurity的NullPointerException产生 01 异常发生场景 当我使用springsecurity请求后端数据时 以下是报错代码 02 问题的产生原因 发生空指针异常,无非就几种 类对象没有初始化,地址默认为null指向的数据为空查找到的数据为空与数据类型冲突 …

最长连续递增序列

最长连续递增序列 描述 : 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 …

92基于matlab的引力搜索算法优化支持向量机(GSA-SVM)分类模型

基于matlab的引力搜索算法优化支持向量机&#xff08;GSA-SVM&#xff09;分类模型&#xff0c;以分类精度为优化目标优化SVM算法的参数c和g&#xff0c;输出分类可视化结果及适应度变化曲线。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 92 引力搜索算法…

数据结构 / 队列 / 循环队列 / 概念

1. 定义 为充分利用向量空间&#xff0c;克服假溢出现象的方法是&#xff1a;将向量空间想象为一个首尾相接的圆环&#xff0c;并称这种向量为循环向量。存储在其中的队列称为循环队列&#xff08;Circular Queue&#xff09;。循环队列是把顺序队列首尾相连&#xff0c;把存储…

如何下载IEEE出版社的Journal/Conference/Magazine的LaTeX/Word模板

当你准备撰写一篇学术论文或会议论文时&#xff0c;使用IEEE&#xff08;电气和电子工程师协会&#xff09;的LaTeX或Word模板是一种非常有效的方式&#xff0c;它可以帮助你确保你的文稿符合IEEE出版的要求。无论你是一名研究生生或一名资深学者&#xff0c;本教程将向你介绍如…

OpenTelemetry系列 - 第3篇 OpenTelemetry Collector

目录 一、介绍Collector二、安装Collector2.1 Docker方式2.2 Windows系统安装 三、配置Collector四、exporter配置4.1 导出到Skywalking4.1.1 导出metrics、logs4.1.2 通过zipkin导出traces到Skywalking 4.2 导出到Jaeger4.3 导出到zipkin4.4 导出到Prometheus4.4.1 Prometheus…

【报名】2023产业区块链生态日暨 FISCO BCOS 开源六周年生态大会

作为2023深圳国际金融科技节系列活动之一&#xff0c;由深圳市地方金融监督管理局指导&#xff0c;微众银行、金链盟主办的“2023产业区块链生态日暨FISCO BCOS开源六周年生态大会”将于12月15日下午14:00在深圳举办。 今年的盛会将进一步升级&#xff0c;以“FISCO BCOS和TA的…

20231202将RK3399的挖掘机开发板在Andorid12系统下编译ENG模式

20231202将RK3399的挖掘机开发板在Andorid12系统下编译ENG模式 2023/12/2 10:21 百度搜索&#xff1a;RK3399 编译 ENG版本 RK3399 lunch ENG Z:\rk_android12_220722\device\rockchip\rk3399\AndroidProducts.mk # # Copyright 2014 The Android Open-Source Project # # Lice…

php5构造无字母数字的webshell实现任意命令执行

目录 引言 如果是在php7 如果是在php5 现在我们来上传文件 最后的结果&#xff1a; 看本篇前可以先看这一篇&#xff1a;利用异或、取反、自增bypass_webshell_waf-CSDN博客 引言 上一篇介绍了如何构造出一个无字母数字的webshell&#xff0c;但是如果后端的代码变成了这…

采购业务中的主数据

目录 一、维护BP主数据业务伙伴BP的概念业务伙伴涉及的表业务伙伴维护操作一次性客商数据 二、维护物料主数据三、维护采购信息记录四、与FI相关集成点物料主数据的价格控制评估类与科目确定 一、维护BP主数据 业务伙伴BP的概念 在S/4HANA中&#xff0c;SAP引入了BP(Business…

使用 Java 来完成高德地图开发平台解决定位和解析问题

三军可夺帅也&#xff0c;匹夫不可夺志也 1、高德开发平台&#xff1a;平台地址 2、注册高德开发平台账号 3、导入SDK J版 import java.net.URL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSONObject;public class main {priva…

SpringBoot整合Activiti7——消息事件(十)

文章目录 消息事件开始事件中间事件边界事件代码实现xml文件测试流程流程执行步骤 消息事件 消息事件只有一个接收者&#xff0c;消息具有名字与载荷。 信息会储存在 act_ru_event_subscr 表中。 <!-- 定义消息 --> <message id"msgId1" name"msgName…

聊聊什么是IO流

目录 Java IOIO 基础Java IO 流了解吗&#xff1f; IO 设计模式1、装饰器模式2、适配器模式适配器模式和装饰器模式有什么区别呢&#xff1f;3、工厂模式4、观察者模式 IO 模型有哪些常见的 IO 模型&#xff1f;BIO(Blocking I/O)NIO (Non-blocking/New I/O)AIO (Asynchronous …

51单片机的智能加湿器控制系统【含proteus仿真+程序+报告+原理图】

1、主要功能 该系统由AT89C51单片机LCD1602显示模块DHT11湿度传感器模块继电器等模块构成。主要适用于智能自动加湿器、湿度保持、湿度控制等相似项目。 可实现基本功能: 1、LCD1602液晶屏实时显示湿度信息 2、DHT11采集湿度 3、按键可以调节适宜人体湿度的阈值范围&#xff0…

西南科技大学模拟电子技术实验三(BJT单管共射放大电路测试)预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 二、画出并填写实验指导书上…

京东数据运营-京东数据开放平台-鲸参谋10月粮油调味市场品牌店铺销售数据分析

鲸参谋监测的京东平台10月份料油调味市场销售数据已出炉&#xff01; 根据鲸参谋数据显示&#xff0c;今年10月份&#xff0c;京东平台粮油调味市场的销量将近4600万&#xff0c;环比增长约10%&#xff0c;同比降低约20%&#xff1b;销售额将近19亿&#xff0c;环比增长约4%&am…

Apache Flink(一):Apache Flink是什么?

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

五、ZooKeeper的shell操作

目录 1、客户端连接 2、shell基本操作 2.1 操作命令