mybatis系列-tkmybatis-10-pagehelper分页原理及源码分析

2024-06-19 18:32

本文主要是介绍mybatis系列-tkmybatis-10-pagehelper分页原理及源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近在写Mybatis系列文章,pageHelper在物理分页上用的比较多,这里就通过源码对它的原理进行分析

tkmybatis源码版本:

<dependency>

    <groupId>com.github.pagehelper</groupId>

    <artifactId>pagehelper-spring-boot-starter</artifactId>

    <version>1.2.12</version>

</dependency>

目录

一、使用案例:

二、整体流程:

三、源码解析:

1、添加mybatis拦截器

    a、加载PageHelperAutoConfiguration配置

   b、添加mybatis拦截器

2、执行分页查询

    a、Page实例创建

 b、查询操作 

3、拦截器是怎么生效的


一、使用案例:

参考《003-数据库-tkmybatis-04-SpringBoot整合TkMybatis+PageHelper实现分页查询》

二、整体流程:

pageHelper实现物理分页的流程大概分为以下几步:

  • 在依赖包pagehelper-spring-boot-autoconfigure.jar中的spring.factories文件内默认配置了jar包被Spring加载后自动加载到容器中的配置类com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration,这是一切的起点(可参考Spring如何通过SPI机制实现服务动态配置)

  • 在PageHelperAutoConfiguration配置类中的@PostConstruct方法里为mybatis的每一个SqlSessionFactory中的Configuration添加mybatis的拦截器

  • 执行查询操作

  • 调用拦截StatementHandler(Sql语法的构建处理)方法,按照物理库的不同重构SQL实现分页

  • 返回查询结果

 

三、源码解析:

 

1、添加mybatis拦截器

     像整体流程中说的那样,Spring加载pageHelper的时候,pageHelper会首先通过配置类PageHelperAutoConfiguration,向SqlSessionFactory添加mybatis的拦截器,我们来看下具体过程。

 

    a、加载PageHelperAutoConfiguration配置

        如下图所示,pagehelper-spring-boot-autoconfigure.jar中的spring.factories设置了org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration,所以Spring在加载该jar包的时候,就会将该PageHelperAutoConfiguration类作为一个配置bean加入到容器中。

   b、添加mybatis拦截器

        我们来分析下PageHelperAutoConfiguration类,看下是怎么添加拦截器的。如下图所示,PageHelperAutoConfiguration类注解有几个限制,必须存在SqlSessionFactory类的实例才会生效,在mybatis配置完成后才开始执行。

重点看下 @PostConstruct注解的方法,在该bean完成参数注入后,容器会调用该方法。

        注意这里会有多个SqlSessionFactory,像mybatis实现多数据源操作的时候,就会添加多个SqlSessionFactory。所以在PageHelper中会对每个SqlSessionFactory都添加拦截。

到这里,拦截器就添加完成了,拦截器内进行了什么操作,我们在查询的时候再分析。

 

2、执行分页查询

    a、Page实例创建

    下图就是我们执行分页查询时写的代码,PageHelper.startPage这个静态方法执行后,后续查询就会返回分页的结果。

跟进去startPage,看里面做了什么。

    如下图所示,startPage方法,创建了Page对象,然后通过setLocalPage方法,将该对象放到了ThreadLocal中(为了保证线程安全,即一个线程一个Page对象用于分页)

 b、查询操作 

        设置好了Page对象,这个对象是怎么用的呢,我们继续看执行查询操作的时候,发生了什么。以上一步截图中的List<Orders> result = ordersMapper.selectAll()查询为例。我们在第1步添加的拦截器PageInterceptor中的intercept方法添加断点,会发现,执行selectAll操作的时候,系统进到了拦截器中断点的位置,我们来看下,拦截器做了些什么。(拦截器是怎么生效的,即mybatis是怎么调用的该拦截器的intercept方法,这个复杂一点,我们放到最后说,先看下intercept方法里做了些什么)

        intercept的操作如下图所示,这里可以看到,Page是否设置,影响着我们是否进行分页。另外有一个需要注意,在查询总数的时候,即count函数里面,PageHelper会根据MappedStatement的Id和"_COUNT"后缀,创建唯一的标识countMsId,如果查询条件没有改变(分页条件除外),则该countMsId是一样的,PageHelper会将count查询的结果用countMsId作为key存在Map中,供下次查询使用,从而避免每次分页查询的时候都去在数据库中重新计算count的值。

    再进一步看下pageQuery中是如何进行分页的。

在生成pageSql的时候,系统会根据数据库类型,选择不同的dialect进行pageSql的创建,比如我们这里用的是MySqlDialect。pageSql创建好后,后面执行的分页查询executor.query这些就是mybatis的查询操作了,我们这里就不细讲。

至此,我们就完成了查询Sql的修改以及分页查询。

3、拦截器是怎么生效的

        在第2步中,还有个遗留问题,拦截器是怎么生效的?其实这部分属于mybatis的内容,这里简单分析一下。回看下第1步,在下面的函数中,pageHelper添加了拦截器。

我们分析下addInterceptor方法所属的类,该类中还有个pluginAll方法。该方法会在执行SQL的时候调用。我们知道,每次执行SQL,mybatis都会为该操作生成一个sqlsession的对象,sqlsession对象生成时会生成一个executor(sql的实际执行类,在前面我们也能看见,改造后的分页sql就是用该类的方法来执行实际查询的),在生成executor的时候,mybatis会依次调用interceptors中添加的拦截器(注意这个拦截器不是spring的拦截器)的plugin方法,对executor进行处理。

我们继续看下PageInterceptor这个PageHelper的拦截器,在plugin方法中做了什么。

如下图,在wrap方法中,创建了executor的代理类Plugin(可以参考JDK动态代理是如何实现的)。

executor在执行Sql处理的时候,就会跳转到Plugin的invoke方法中,返回该方法的结果。invoke方法如下,因为在创建代理类Plugin时就把PageInterceptor传入了进去,所以在invoke方法中,就实现了PageInterceptor的intercept方法对SQL操作进行处理。至此就解决了拦截器是怎么生效的问题,后续的intercept的内容,就是第2步b部分的内容了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于mybatis系列-tkmybatis-10-pagehelper分页原理及源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

MyBatis-Plus 自动赋值实体字段最佳实践指南

《MyBatis-Plus自动赋值实体字段最佳实践指南》MyBatis-Plus通过@TableField注解与填充策略,实现时间戳、用户信息、逻辑删除等字段的自动填充,减少手动赋值,提升开发效率与... 目录1. MyBATis-Plus 自动赋值概述1.1 适用场景1.2 自动填充的原理1.3 填充策略

mybatis中resultMap的association及collectio的使用详解

《mybatis中resultMap的association及collectio的使用详解》MyBatis的resultMap定义数据库结果到Java对象的映射规则,包含id、type等属性,子元素需... 目录1.reusltmap的说明2.association的使用3.collection的使用4.总