MybatisPlus的分页插件
PaginationInnerInterceptor
此插件是核心插件,目前代理了 Executor#query 和 Executor#update 和 StatementHandler#prepare 方法。
在SpringBoot环境中配置方式如下:
/*** @author giserDev* @description 配置分页插件、方言、mapper包扫描等* @date 2023-12-13 23:23:35*/
@Configuration
@MapperScan("com.giser.mybatisplus.mapper")
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return mybatisPlusInterceptor;}}
测试分页功能:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.giser.mybatisplus.mapper.UserMapper;
import com.giser.mybatisplus.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;/*** @author giserDev* @description* @date 2023-12-13 23:28:43*/
@Slf4j
@SpringBootTest
public class MyBatisPlusPluginsTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testMyBatisPlusPage(){Page<User> page = new Page<>(1,3);userMapper.selectPage(page, null);log.info("分页查询结果为:{}", page);}}
如何自定义分页?
# mybatis-plus配置
mybatis-plus:configuration:# 引入日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:# 配置MybatisPlus操作的表的前缀table-prefix: t_# 配置MybatisPlus的主键生成策略id-type: assign_id# 指定类型别名type-aliases-package: com.giser.mybatisplus.pojo
在Mapper接口中定义分页方法:
@Repository
public interface UserMapper extends BaseMapper<User> {/*** 利用MybatisPlus的分页功能* @param page 分页对象,必须在第一个参数位置,传递参数 Page 即自动分页* @param userName 查询条件* @return 结果*/Page<User> selectPageByName(@Param("page") Page<User> page, @Param("userName") String userName);}
在Mapper.xml文件中实现分页语句:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.giser.mybatisplus.mapper.UserMapper"><select id="selectPageByName" resultType="User">select * from user where user_name = #{userName}</select></mapper>
分页测试:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.giser.mybatisplus.mapper.UserMapper;
import com.giser.mybatisplus.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@Slf4j
@SpringBootTest
public class MyBatisPlusPluginsTest {@Autowiredprivate UserMapper userMapper;/*** ==> Preparing: SELECT COUNT(*) AS total FROM user WHERE is_deleted = 0* ==> Parameters:* <== Columns: total* <== Row: 25* <== Total: 1* ==> Preparing: SELECT id,user_name AS name,age,email,is_deleted FROM user WHERE is_deleted=0 LIMIT ?* ==> Parameters: 3(Long)* <== Columns: id, name, age, email, is_deleted* <== Row: 1, Jone, 18, test1@baomidou.com, 0* <== Row: 2, 窃听风云, 23, giserDev@163.com, 0* <== Row: 3, Tom, 28, test3@baomidou.com, 0* <== Total: 3* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3a109ff7]* 分页查询结果为:com.baomidou.mybatisplus.extension.plugins.pagination.Page@5ee77baf* 分页查询记录结果为:[User(id=1, name=Jone, age=18, email=test1@baomidou.com, isDeleted=0), User(id=2, name=窃听风云, age=23, email=giserDev@163.com, isDeleted=0), User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=0)]* 分页查询记录条数为:25* 分页查询当前页码为:1* 分页查询每页大小为:3*/@Testpublic void testMyBatisPlusPage(){Page<User> page = new Page<>(1,3);userMapper.selectPage(page, null);log.info("分页查询结果为:{}", page);log.info("分页查询记录结果为:{}", page.getRecords());log.info("分页查询记录条数为:{}", page.getTotal());log.info("分页查询当前页码为:{}", page.getCurrent());log.info("分页查询每页大小为:{}", page.getSize());}/*** ==> Preparing: SELECT COUNT(*) AS total FROM user WHERE user_name = ?* ==> Parameters: 李雷(String)* <== Columns: total* <== Row: 1* <== Total: 1* ==> Preparing: select * from user where user_name = ? LIMIT ?* ==> Parameters: 李雷(String), 3(Long)* <== Columns: id, user_name, age, email, is_deleted* <== Row: 1734579107187970050, 李雷, 12, null, 1* <== Total: 1* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@a316f6b]* 分页查询结果为:com.baomidou.mybatisplus.extension.plugins.pagination.Page@48368a08* 分页查询记录结果为:[User(id=1734579107187970050, name=null, age=12, email=null, isDeleted=1)]* 分页查询记录条数为:1* 分页查询当前页码为:1* 分页查询每页大小为:3*/@Testvoid testAutoPage(){Page<User> page = new Page<>(1,3);userMapper.selectPageByName(page, "李雷");log.info("分页查询结果为:{}", page);log.info("分页查询记录结果为:{}", page.getRecords());log.info("分页查询记录条数为:{}", page.getTotal());log.info("分页查询当前页码为:{}", page.getCurrent());log.info("分页查询每页大小为:{}", page.getSize());}}
问题:分页参数处理原理
拦截执行的语句
org.apache.ibatis.plugin.Plugin#invoke
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor#intercept
@Overridepublic Object intercept(Invocation invocation) throws Throwable {// ...for (InnerInterceptor query : interceptors) {// com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor#willDoQuery// willDoQuery(),先判断总条数,决定是否执行sql语句if (!query.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql)) {return Collections.emptyList();}// beforeQuery(),处理排序、分页方言query.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
}// ...
@Overridepublic boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {// 查找分页参数IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);if (page == null || page.getSize() < 0 || !page.searchCount()) {return true;}// ...// 组装统计语句,判断总条数long total = 0;if (CollectionUtils.isNotEmpty(result)) {// 个别数据库 count 没数据不会返回 0Object o = result.get(0);if (o != null) {total = Long.parseLong(o.toString());}}page.setTotal(total);// protected boolean continuePage(IPage<?> page)// 返回是否继续执行后面的查询语句,执行则返回true,否则返回falsereturn continuePage(page);}
willDoQuery()方法中包含查询分页参数的逻辑,如下:
/*** 查找分页参数** @param parameterObject 参数对象* @return 分页参数*/
public static Optional<IPage> findPage(Object parameterObject) {if (parameterObject != null) {// 若参数类型为Map,则从map中查找类型为IPage的参数,作为分页参数if (parameterObject instanceof Map) {Map<?, ?> parameterMap = (Map<?, ?>) parameterObject;for (Map.Entry entry : parameterMap.entrySet()) {if (entry.getValue() != null && entry.getValue() instanceof IPage) {return Optional.of((IPage) entry.getValue());}}} else if (parameterObject instanceof IPage) {// 若参数类型为IPage,则直接返回,作为分页参数return Optional.of((IPage) parameterObject);}}return Optional.empty();
}
com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor#beforeQuery
@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);if (null == page) {return;}// 处理 orderBy 拼接boolean addOrdered = false;String buildSql = boundSql.getSql();List<OrderItem> orders = page.orders();if (CollectionUtils.isNotEmpty(orders)) {addOrdered = true;buildSql = this.concatOrderBy(buildSql, orders);}// size 小于 0 且不限制返回值则不构造分页sqlLong _limit = page.maxLimit() != null ? page.maxLimit() : maxLimit;if (page.getSize() < 0 && null == _limit) {if (addOrdered) {PluginUtils.mpBoundSql(boundSql).sql(buildSql);}return;}handlerLimit(page, _limit);// 查找方言,在配置分页插件时,设置了DbType,此时可确定方言,如此时返回的是com.baomidou.mybatisplus.extension.plugins.pagination.dialects.MySqlDialectIDialect dialect = findIDialect(executor);final Configuration configuration = ms.getConfiguration();// 构造分页语句!!!com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect#buildPaginationSql// 此时dialect为MySqlDialect,会调用com.baomidou.mybatisplus.extension.plugins.pagination.dialects.MySqlDialect#buildPaginationSql来构造sqlDialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize());// ...// 此处绑定执行的sql语句model.getDialectSql()mpBoundSql.sql(model.getDialectSql());mpBoundSql.parameterMappings(mappings);}
com.baomidou.mybatisplus.extension.plugins.pagination.dialects.MySqlDialect#buildPaginationSql
public class MySqlDialect implements IDialect {@Overridepublic DialectModel buildPaginationSql(String originalSql, long offset, long limit) {StringBuilder sql = new StringBuilder(originalSql).append(" LIMIT ").append(FIRST_MARK);if (offset != 0L) {sql.append(StringPool.COMMA).append(SECOND_MARK);return new DialectModel(sql.toString(), offset, limit).setConsumerChain();} else {return new DialectModel(sql.toString(), limit).setConsumer(true);}}
}
相关文章:
MybatisPlus的分页插件
PaginationInnerInterceptor 此插件是核心插件,目前代理了 Executor#query 和 Executor#update 和 StatementHandler#prepare 方法。 在SpringBoot环境中配置方式如下: /*** author giserDev* description 配置分页插件、方言、mapper包扫描等* date 2023-12-13 …...
保障网络安全:了解威胁检测和风险评分的重要性
在当今数字时代,网络安全问题变得愈发突出,而及时发现和迅速应对潜在威胁成为保障组织信息安全的首要任务。令人震惊的是,根据2023年的数据,平均而言,检测到一次网络入侵的时间竟然长达207天。这引起了对安全策略和技术…...
3D摄影棚布光:Set A Light 3D Studio
Set A Light 3D Studio是一款专业的灯光模拟软件,旨在帮助摄影师和电影制片人在电脑上进行虚拟灯光布置和场景模拟,以实现更加精准和高质量的拍摄效果。该软件提供了丰富的灯光和场景模型,支持灵活调整光源位置、强度、颜色和效果等参数&…...
#HarmonyOS:应用的包名配置--应用图标和标签配置--配置链接
配置相关 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/application-component-configuration-stage-0000001478340869-V2 应用的包名配置 应用需要在工程的AppScope目录下的app.json5配置文件中配置bundleName标签,该标签用于标识应用的唯…...
docker小白第三天
docker小白第三天 docker为什么会比虚拟机快 1、docker有着比虚拟机更少的抽象层。不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源,因此在CPU、内存利用率上docker将会在效率上有明显优势。 2、dock…...
FFmpegd的AVBSF
本章主要介绍AVBSF 文章目录 结构体定义对外函数常见的过滤器 从名字我们可以知道这是个码流过滤器,我们最常用的是一个叫做h264_mp4toannexb_bsf的东东 这个过滤器的作用是把h264以MP4格式的NALU转换为annexb(0x000001) const AVBitStreamF…...
深圳三男子写字楼内吸烟被罚,快用富维AI神器,实时监控防火灾
最近,在深圳,一专项控烟督查组在福田区新华保险大厦发现三名男子在写字楼内楼道违法吸烟,并对其进行了现场处罚。根据《控烟条例》,这类室内区域严禁吸烟,但人们往往忽视这一规定,从而引发潜在的安全风险。…...
有哪些已经上线的vue商城项目?
前言 下面是一些商城的项目,需要练手的同学可以挑选一些来练,废话少说,让我们直接开始正题~~ 1、newbee-mall-vue3-app 是一个基于 Vue 3 和 TypeScript 的电商前端项目,它是 newbee-mall 项目的升级版。该项目包含了商品列表、…...
Nginx服务器配置SSL证书
本文将全面介绍如何在Nginx或Tengine服务器配置SSL证书,具体包括下载和上传证书文件,在Nginx上配置证书文件、证书链和证书密钥等参数,以及安装证书后结果的验证。成功配置SSL证书后,您将能够通过HTTPS加密通道安全访问Nginx服务器…...
【JVM从入门到实战】(六)类加载器的双亲委派机制
一、双亲委派机制 在Java中如何使用代码的方式去主动加载一个类呢? 方式1:使用Class.forName方法,使用当前类的类加载器去加载指定的类。 方式2:获取到类加载器,通过类加载器的loadClass方法指定某个类加载器加载。 …...
SpringCloud面试题及答案(最新50道大厂版,持续更新)
在Java开发中,Spring Cloud作为微服务架构的关键组成部分,为了帮助广大Java技术爱好者和专业开发人员深入理解Spring Cloud,本文《SpringCloud面试题及答案(最新50道大厂版,持续更新)》提供了最前沿、最实用…...
Next.js 的设计理念
Next.js 的设计理念:简洁、强大与高效 Next.js 是一个流行的 React 框架,由 Vercel 公司开发。它的设计理念是简洁、强大和高效,这种理念贯穿于 Next.js 的所有功能中。下面我们将深入探讨这三个设计理念。 简洁 Next.js 的一个核心设计理…...
26、文件包含
文章目录 一、文件包含1.1 概念1.2 PHP文件包含原理1.3 文件包含重要函数1.4 文件包含利用条件 二、文件包含漏洞利用2.1 文件包含分类2.2 常见敏感文件2.3 包含Apache日志文件2.4 常见中间件的日志路径2.5 包含其他日志文件2.5.1 SSH日志文件2.5.2 Session文件 三、PHP封装伪协…...
飞天使-linux操作的一些技巧与知识点4-ansible常用的技巧,配置等
文章目录 ansible配置文件的优先级尝试开始进行操作ansible常用模块ansible 的playbook示例安装phpplaybook中变量的引用 ansible yum install -y ansible 测试是否可用 ansible localhost -m ping /etc/ansible/ansible.cfg :主配置文件,配置 ansible…...
Stable Diffusion 源码解析(1)
参考1:https://blog.csdn.net/Eric_1993/article/details/129393890 参考2:https://zhuanlan.zhihu.com/p/613337342 1.StableDiffusion基本原理1.1 UNetModel、FrozenCLIP 模型1.2 DDPM、DDIM、PLMS算法 2. Runwayml SD 源码2.1 Img2Img Pipeline2.2 DD…...
java.lang.ClassNotFoundException:javax.xml.bind.DatatypeConverter 报错解决
问题原因: 这有可能是因为SpringBoot项目结合jwt进行用户登录时出现的问题,因为jdk版本太高导致的 解决办法: 方法一: 降低jdk版本 检查JDK版本,如果你是JDK17版本,就降到JDK8版本 方案二:在meven中添加依赖 注意: 如果2.3.1的版本不生效,则使用2.3.0的版本 <…...
Python学习笔记-类
1 定义类 类是函数的集合,class来定义类 pass并没有实际含义,只是为了代码能执行通过,不报错而已,相当于在代码种占一个位置,后续完善 类是对象的加工厂 2.创建对象 carCar()即是创建对象的过程 3、类的成员 3.1 实例…...
了解如何在linux使用podman管理容器
本章主要介绍使用 podman 管理容器。 了解什么是容器,容器和镜像的关系 安装和配置podman 拉取和删除镜像 给镜像打标签 导出和导入镜像 创建和删除镜像 数据卷的使用 管理容器的命令 使用普通用户管理容器 使用普通用户管理容器 对于初学者来说,不太容…...
SQL命令---修改字段的数据类型
介绍 使用sql语句修改字段的数据类型。 命令 alter table 表明 modify 字段名 数据类型;例子 有一张a表,表里有一个id字段,长度为11。使用命令将长度修改为12 下面使用命令进行修改: alter table a modify id int(12) NOT NULL;下面使修…...
一键提取微信聊天记录,生成HTML、Word文档永久保存,还能生成微信年度聊天报告
不知道生活中你有没有遇到过这种情况,聊天记录不完整,有的在手机上,有的在电脑上,搜索起来很烦。那有没有一种办法可以把微信聊天记录统一呢?当然是有的。下面,就让我们一起来看一下怎么操作。 先看效果 操…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
LeetCode 0386.字典序排数:细心总结条件
【LetMeFly】386.字典序排数:细心总结条件 力扣题目链接:https://leetcode.cn/problems/lexicographical-numbers/ 给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。 你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。…...
