MyBatis是如何分页的及原理

MyBatis 是一种持久层框架,支持通过配置文件和注解将 SQL 映射为 Java 对象。在实际开发中,查询数据时经常需要进行分页处理。 MyBatis 也提供了支持分页的方案,其主要思路是使用 Limit 偏移量和限制个数,来获取指定数量的数据。下面将会介绍 MyBatis 如何进行分页。

MyBatis 提供两种分页方式:基于参数改造和基于插件拦截 。下面我们将分别介绍这两种方式:

1、基于参数改造:

第一种分页方式是基于参数改造的,通过添加参数 limit 和 offset 就可以实现查询从某个位置开始的若干条记录,代码实现如下:

<select id="selectSomeData"parameterType="map" resultType="com.example.SomeData">SELECT * FROM sometableORDER BY somecolumnLIMIT #{limit} OFFSET #{offset}
</select>

这段 SQL 语句会返回从偏移量为 offset 的位置开始的 limit 条结果。例如:LIMIT 30,10 表示从第 31 行开始返回 10 行结果。

在实际应用中,我们可以将 limit 和 offset 抽取成两个参数,并传入到 MyBatis 中。

2、基于插件拦截 :

MyBatis 还提供了另外一种分页方式,基于插件拦截机制。这种方式更加灵活,支持实现更为复杂的分页功能。

我们需要自定义一个拦截器,实现 Interceptor 接口,并重写其中唯一的 intercept 方法,在其中对 SQL 语句进行修改,添加分页信息。具体操作如下:

首先,创建一个类来实现该拦截器:

public class PageInterceptor implements Interceptor {/*** 拦截方法** @param invocation* @return* @throws Throwable*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取原始的SQL语句String sql = (String) invocation.getArgs()[0];// 查询总数并计算出总页数和当前页int total = count(sql);// 如果总数小于等于0,则直接返回空结果集if (total <= 0) {return Collections.emptyList();}// 计算出当前页的起始位置和结束位置int offset = getOffset(pageNo, pageSize);int limit = pageSize;// 构造含分页信息的新SQLString newSql = getNewSql(sql, offset, limit);// 将新SQL替换成原来的SQL,并继续执行原有方法ReflectionUtils.setFieldValue(invocation, "h.sql", newSql);Object result = invocation.proceed();// 包装成Page对象,并返回Page<T> pageResult = new Page<>(pageNo,pageSize,total,(List<T>)result);return pageResult;}/*** 获取新的SQL语句(含分页信息)** @param sql* @param offset* @param limit* @return*/private String getNewSql(String sql, int offset, int limit) {return sql + " LIMIT " + offset + "," + limit;}/*** 获取查询结果总数** @param sql* @return*/private int count(String sql){// code omitted}/*** 计算当前分页的 Offset** @param pageNo* @param pageSize* @return*/private int getOffset(int pageNo, int pageSize) {return (pageNo - 1) * pageSize;}
}

然后,我们需要在 mybatis-config.xml 配置文件中注册该拦截器:

<plugins><plugin interceptor="com.example.mybatis.PageInterceptor"/>
</plugins>

最终,在查询数据时,我们便可以按照以下方式进行分页处理了:

public List<User> selectUserListByPage(int startRow, int pageSize){RowBounds rowBounds = new RowBounds(startRow,pageSize);String statement = "com.example.UserMapper.selectUserList";return sqlSession.selectList(statement,null,rowBounds);
}

实现原理简述

  1. 注册拦截器:PageHelper插件通过MyBatis的插件机制注册为一个拦截器,主要拦截Executor接口的query方法。

  2. 动态修改SQL:拦截器在执行query方法前,检查是否有分页信息,如果有,则根据分页参数(如当前页、每页数量)修改SQL,添加分页限制。

  3. 数据库方言:考虑到不同的数据库有不同的分页语法,PageHelper支持多种数据库方言,会根据配置自动选择合适的分页实现。

  4. 执行并返回结果:修改后的SQL被执行,返回的结果是分页后的数据集。

查询电影数据案例
准备工作

首先,确保已经引入了PageHelper依赖,并在MyBatis的配置文件中配置了PageHelper插件,指定数据库方言,例如针对MySQL:

mybatis-config.xml:

<configuration><!-- ... --><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><property name="helperDialect" value="mysql"/></plugin></plugins><!-- ... -->
</configuration>

定义Mapper接口和映射文件 

MovieMapper.java:

public interface MovieMapper {List<Movie> selectMovies();
}

MovieMapper.xml:

<mapper namespace="com.example.mapper.MovieMapper"><select id="selectMovies" resultType="com.example.entity.Movie">SELECT * FROM movie</select>
</mapper>
分页查询示例代码

在服务类中,使用PageHelper进行分页查询:

MovieService.java:

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;@Service
public class MovieService {@Autowiredprivate MovieMapper movieMapper;public Page<Movie> getMoviesByPage(int pageNum, int pageSize) {// 开启分页PageHelper.startPage(pageNum, pageSize);// 执行查询,PageHelper会自动进行分页处理List<Movie> movies = movieMapper.selectMovies();// 返回分页对象,包含了分页信息和数据列表return (Page<Movie>) movies;}
}

在这个例子中,当调用getMoviesByPage方法时,首先通过PageHelper.startPage(pageNum, pageSize)设置分页信息。随后,当调用movieMapper.selectMovies()执行查询时,PageHelper拦截了这次查询请求,根据前面设置的分页参数动态地在SQL查询语句末尾添加了适合MySQL数据库的LIMIT和OFFSET子句,从而只获取当前页面所需的数据。最后,返回的是一个包含了当前页数据以及分页元数据(如总页数、总记录数等)的Page对象。

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

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

相关文章

音视频入门基础:H.264专题(10)——FFmpeg源码中,存放SPS属性的结构体和解码SPS的函数分析

一、引言 FFmpeg源码对AnnexB包装的H.264码流解码过程中&#xff0c;通过ff_h2645_extract_rbsp函数拿到该H.264码流中的某个NALU的NALU Header RBSP后&#xff08;具体可以参考&#xff1a;《FFmpeg源码&#xff1a;ff_h2645_extract_rbsp函数分析》&#xff09;&#xff0c…

【沐风老师】3DMAX建筑体块生成插件BuildingBlocks使用方法详解

BuildingBlocks建筑体块生成插件使用方法详解 听说你还在手动建配景楼&#xff1f;有了BuildingBlocks这个插件&#xff0c;一分钟搞定喔&#xff01; 3DMAX建筑体块生成插件BuildingBlocks&#xff0c;用于快速自定义街道及生成配景楼区块。 【适用版本】 3dMax2019及更高版…

空间分析在3D应用中的革命:提升投资回报与业务价值

在3D应用的浪潮中&#xff0c;空间分析技术正成为提升用户体验、优化业务决策和解决复杂问题的关键工具。本文将深入探讨空间分析如何通过提供深度用户行为洞察和数据可视化&#xff0c;增强3D应用的实际效益和市场竞争力。 一、空间分析的概念与背景 Tony Bevilacqua&#x…

分布式I/O从站的认知

为什么需要分布式I/O从站&#xff1f; 当PLC与控制机构距离过远时&#xff0c;远距离会带来信号干扰&#xff0c;分布式I/O从站只需要一个网络线缆连接。 ET200分布式I/O从站家族 体积紧凑、功能强大。 ET200SP ET200M ET200S ET200iSP ET200 AL ET200pro ET200 eco PN 通讯协议…

DSSM双塔特征交互

传统的DSSM双塔无法在早期进行user和item侧的特征交互&#xff0c;这在一定程度上降低了模型性能。我们想要对双塔模型进行细粒度的特征交互&#xff0c;同时又不失双塔模型离线建向量索引的解耦性。下面介绍两篇这方面的工作。 美团-Dual Augmented Two-tower 在user和item的特…

1. CSS Grid 网格布局教程

CSS Grid 网格布局教程 一、概述 网格布局&#xff08;Grid&#xff09;是最强大的 CSS 布局方案。 它将网页划分成一个个网格&#xff0c;可以任意组合不同的网格&#xff0c;做出各种各样的布局。以前&#xff0c;只能通过复杂的 CSS 框架达到的效果&#xff0c;现在浏览器…

linux工具应用_VERDI

verdi 1. 基础知识1.1 verdi介绍1.2 fsdb文件2. fsdb dump2.1 1st step-设置环境变量LD_LIBRARY_PATH2.2 2nd step-xrun仿真命令2.3 3rd step-仿真过程中调用fsdb函数dump波形2.3.1 在testbench、top.sv中调用fsdb函数2.3.2 在tcl脚本中用xrun的dump指令(同样要调用fsdb函数)2.…

Scrapy crawl spider 停止工作

Scrapy是一个用于爬取网站数据的流行框架&#xff0c;有时爬虫可能会停止工作&#xff0c;这通常是由多种原因引起的。以下是一些常见问题及其解决方法&#xff1a; 1、问题背景 用户在使用 Scrapy 0.16.2 版本进行网络爬取时遇到问题&#xff0c;具体表现为爬虫在运行一段时间…

Android 开发中 C++ 和Java 日志调试

在 C 中添加堆栈日志 先在 Android.bp 中 添加 ‘libutilscallstack’ shared_libs:["liblog"," libutilscallstack"]在想要打印堆栈的代码中添加 #include <utils/CallStack.h> using android::CallStack;// 在函数中添加 int VisualizerLib_Crea…

生物素结合金纳米粒子(Bt@Au-NPs ) biotin-conjugated Au-NPs

一、定义与特点 定义&#xff1a;生物素结合金纳米粒子&#xff0c;简称BtAu-NPs或biotin-conjugated Au-NPs&#xff0c;是指通过特定的化学反应或物理方法将生物素修饰到金纳米粒子表面&#xff0c;形成稳定的纳米复合材料。 特点&#xff1a; 高稳定性&#xff1a;生物素的修…

重构功能带来的配套改造查找思路

最近在重构项目中的一个基础配置功能&#xff0c;这个功能因为后续的业务变化和最初的缺陷设计导致非常难维护和扩展&#xff0c;使用起来也比较费劲&#xff0c;所以决定花一段时间来对它进行重构&#xff0c;去除一些用不到的设计&#xff0c;简化了使用方式和配置方式&#…

RabbitMQ 迁移

文章目录 1. 导出配置2. 导入配置3. 导出和导入定义&#xff08;如果不需要消息&#xff09;导出定义导入定义 注意事项参考文档 要将 RabbitMQ 的配置&#xff08;包括vhost、exchange等&#xff09;从一个实例迁移到另一个实例&#xff0c;您可以遵循以下步骤&#xff1a; 1.…

【VUE基础】VUE3第七节—Vue Router路由基础

Vue Router 是 Vue 官方的客户端路由解决方案。 客户端路由的作用是在单页应用 (SPA) 中将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面时&#xff0c;URL 会随之更新&#xff0c;但页面不需要从服务器重新加载。 Vue Router 基于 Vue 的组件系统构建&…

LabVIEW在半导体自动化测试中的应用

半导体制造的复杂性和精密度要求极高&#xff0c;每一个生产步骤都需要严格的控制和监测。自动化测试设备在半导体制造中起到了关键作用&#xff0c;通过精密测量和数据分析&#xff0c;确保产品质量和生产效率。本文介绍如何使用LabVIEW结合研华硬件&#xff0c;开发一个用于半…

C语言编程3:运算符,运算符的基本用法

C语言3&#x1f525;&#xff1a;运算符&#xff0c;运算符的基本用法 一、运算符&#x1f33f; &#x1f387;1.1 定义 运算符是指进行运算的动作&#xff0c;比如加法运算符"“&#xff0c;减法运算符”-" 算子是指参与运算的值&#xff0c;这个值可能是常数&a…

自动化测试高级控件交互方法:TouchAction、触屏操作、点按,双击,滑动,手势解锁!

在自动化测试领域中&#xff0c;TouchAction 是一种非常强大的工具&#xff0c;它允许我们模拟用户在设备屏幕上的各种触摸事件。这种模拟不仅限于简单的点击操作&#xff0c;还包括滑动、长按、多点触控等复杂的手势。 点按与双击 点按和双击是触屏设备上最基本的操作之一。…

使用 Qt 和 ECharts 进行数据可视化

文章目录 示例图表预览折线图散点图柱状图使用 Qt 和 ECharts 进行数据可视化一、准备工作1. 安装 Qt2. 准备 ECharts二、在 Qt 中使用 ECharts1. 创建 Qt 项目2. 配置项目文件3. 在 UI 中添加 WebEngineView4. 加载 ECharts三、创建折线图、散点图和柱状图1. 折线图2. 散点图3…

Jupyter Notebook的安装教程

以下是一个详细的 Jupyter Notebook 安装教程&#xff0c;适用于大多数操作系统&#xff1a; Windows 系统 1. 安装 Python 访问 Python 官网&#xff0c;下载并安装适合你系统的 Python 版本。在安装过程中&#xff0c;确保勾选“Add Python 3.x to PATH”选项&#xff0c;…

sizeof跟strlen的用法及差异

sizeof是一个操作符&#xff0c;不是函数&#xff1b; 而strlen是一个库函数&#xff1b; sizeof是计算所占内存空间的&#xff0c;不管你内容是什么&#xff0c;只要知道占多少内存&#xff0c; 而strlen是跟内容有关的&#xff0c;它是计算字符串长度的&#xff08;字符数…

java —— tomcat 部署项目

一、通过 war 包部署 1、将项目导出为 war 包&#xff1b; 2、将 war 包放置在 tomcat 目录下的 webapps 文件夹下&#xff0c;该 war 包稍时便自动解析为项目文件夹&#xff1b; 3、启动 tomcat 的 /bin 目录下的 startup.bat 文件&#xff0c;此时即可从浏览器访问项目首页…