pagehelper 优化自定义分页和排序位置
- pagehelper开源地址
- https://github.com/pagehelper/Mybatis-PageHelper
1.手写Count查询优化
源码分页count时首先是判断是否存在手写的 {业务查询id}_COUNT 的查询count统计
private Long count(Executor executor, MappedStatement ms, Object parameter,RowBounds rowBounds, ResultHandler resultHandler,BoundSql boundSql) throws SQLException {String countMsId = ms.getId() + countSuffix;Long count;//先判断是否存在手写的 count 查询MappedStatement countMs = ExecutorUtil.getExistedMappedStatement(ms.getConfiguration(), countMsId);if (countMs != null) {count = ExecutorUtil.executeManualCount(executor, countMs, parameter, boundSql, resultHandler);} else {if (msCountMap != null) {countMs = msCountMap.get(countMsId);}//自动创建if (countMs == null) {//根据当前的 ms 创建一个返回值为 Long 类型的 mscountMs = MSUtils.newCountMappedStatement(ms, countMsId);if (msCountMap != null) {msCountMap.put(countMsId, countMs);}}count = ExecutorUtil.executeAutoCount(this.dialect, executor, countMs, parameter, boundSql, rowBounds, resultHandler);}return count;}
手写count用法:
<select id="selectReportList" parameterType="xxxx" resultMap="xxx">****业务sql*****
</select >
<select id="selectReportList_COUNT" parameterType="xxxx" resultType="java.lang.Integer"> ****业务sql手写优化count*****
</select >
2.自定义分页排序位置
分页查询时复杂业务需要多表关联查询,关联表越多越影响查询效率;根据业务可将不影响查询结果的表分页后再查询需要自定义分页或排序位置
以mysql为例:
package com.github.pagehelper.dialect.helper;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.RowBounds;import com.github.pagehelper.Page;
import com.github.pagehelper.dialect.AbstractHelperDialect;
import com.github.pagehelper.parser.OrderByParser;
import com.github.pagehelper.util.MetaObjectUtil;
import com.github.pagehelper.util.StringUtil;/*** 重写MySqlDialect满足自定义分页需求,* 类放在package 为 com.github.pagehelper.dialect.helper包覆盖源 码才生效*/
public class MySqlDialect extends AbstractHelperDialect {/*** 自定义分页key:*//*customizeLimit*/public static final String CUSTOMIZE_LIMIT="/\\*customizeLimit\\*/"; public static final Pattern customizeLimitFixed = Pattern.compile(CUSTOMIZE_LIMIT);/*** 自定义排序 key:*//*customizeOrderBy*/public static final String CUSTOMIZE_ORDERBY="/\\*customizeOrderBy\\*/"; public static final Pattern customizeOrderbyFixed = Pattern.compile(CUSTOMIZE_ORDERBY);@Overridepublic Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());//处理pageKeypageKey.update(page.getStartRow());pageKey.update(page.getPageSize());//处理参数配置if (boundSql.getParameterMappings() != null) {List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());if (page.getStartRow() == 0) {newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());} else {newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());}MetaObject metaObject = MetaObjectUtil.forObject(boundSql);metaObject.setValue("parameterMappings", newParameterMappings);}return paramMap;}@Overridepublic String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {String sql = boundSql.getSql();Page page = getLocalPage();//支持 order byString orderBy = page.getOrderBy();if (StringUtil.isNotEmpty(orderBy)) { pageKey.update(orderBy);if(customizeOrderbyFixed.matcher(sql).find()) {//自定义排序位置替换 sql = sql.replaceFirst(CUSTOMIZE_ORDERBY, " order by " + orderBy);}else {//源码逻辑sql = OrderByParser.converToOrderBySql(sql, orderBy);}}if (page.isOrderByOnly()) {return sql;}return getPageSql(sql, page, pageKey);}@Overridepublic String getPageSql(String sql, Page page, CacheKey pageKey) {if(customizeLimitFixed.matcher(sql).find()) {//自定义分页位置替换if (page.getStartRow() == 0) {sql = sql.replaceFirst(CUSTOMIZE_LIMIT, " LIMIT ? ");} else {sql = sql.replaceFirst(CUSTOMIZE_LIMIT, " LIMIT ?, ? ");}return sql;}else {//源码逻辑StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);sqlBuilder.append(sql);if (page.getStartRow() == 0) {sqlBuilder.append("\n LIMIT ? ");} else {sqlBuilder.append("\n LIMIT ?, ? ");}return sqlBuilder.toString();}}}
用法示例
<select id="selectReportList" parameterType="xxxxx" resultType="xxxxx">SELECT tmp.*, ci.xx, ma.xx, mb.xx FROM(SELECT 查询结果FROM xxx puINNER JOIN xxx ccs ON pu.xx= ccs.xxINNER JOIN xxx wui ON wui.xx= pu.xx<where>查询查询条件 </where>/*customizeOrderBy*//*customizeLimit*/) tmpLEFT JOIN xxx ci ON tmp.xx= ci.xxLEFT JOIN xxx ma ON tmp.xx= ma.xx LEFT JOIN xxx mb ON tmp.xx = mb.xx </select>
3.控制查询是否需要Count
- 场景:业务中分页查询列表数据变化实时性不高,分页查询时只有查询第一页才统计count,避免重复的count统计
修改设置请求分页数据方法
/*** 设置请求分页数据(仅第一页查询count数)*/public static void startPageNoCount(){PageDomain pageDomain = TableSupport.buildPageRequest();Integer pageNum = pageDomain.getPageNum();Integer pageSize = pageDomain.getPageSize();String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());Boolean reasonable = pageDomain.getReasonable();if(pageNum.intValue()==1) {//第一页查询countPageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);}else {PageHelper.startPage(pageNum, pageSize, false).setOrderBy(orderBy).setReasonable(reasonable);}}/*** 设置请求分页数据(仅第一页查询count数)*/public static void startPageNoCount(PageDomain pageDomain){pageDomain.setPageNum(Convert.toInt(pageDomain.getPageNum(), 1));pageDomain.setPageSize(Convert.toInt(pageDomain.getPageSize(), 10));Integer pageNum = pageDomain.getPageNum();Integer pageSize = pageDomain.getPageSize();String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderByNoScoreCase());//直接驼峰参数拼接Boolean reasonable = pageDomain.getReasonable();if(pageNum.intValue()==1) {//第一页查询countPageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);}else {PageHelper.startPage(pageNum, pageSize, false).setOrderBy(orderBy).setReasonable(reasonable);}}
原理基于 PageMethod.class 中startPage 方法控制实现
/*** 开始分页** @param pageNum 页码* @param pageSize 每页显示数量* @param count 是否进行count查询*/public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) {return startPage(pageNum, pageSize, count, null, null);}
相关文章:
pagehelper 优化自定义分页和排序位置
pagehelper开源地址 https://github.com/pagehelper/Mybatis-PageHelper 1.手写Count查询优化 源码分页count时首先是判断是否存在手写的 {业务查询id}_COUNT 的查询count统计 private Long count(Executor executor, MappedStatement ms, Object parameter,RowBounds rowBound…...
Linux下查询文件夹中文件数量的方法
一、前言 在Linux系统中,我们经常需要查询文件夹中包含多少文件。本文将介绍三种在Linux中查询文件夹中文件数量的方法,帮助你轻松获取所需信息。 二、方法 1、使用ls命令和wc命令 使用ls命令的-l选项和管道操作符|结合wc命令来统计文件数量…...
PS透明屏,在科技展示中,有哪些优点展示?
PS透明屏是一种新型的显示技术,它将传统的显示屏幕与透明材料相结合,使得屏幕能够同时显示图像和透过屏幕看到背后的物体。 这种技术在商业展示、广告宣传、产品展示等领域有着广泛的应用前景。 PS透明屏的工作原理是利用透明材料的特性,通…...
Hbase-面试题
1. Hbase-region切分 自动切分,默认情况下 2.0版本,第一次region的数据达到256M,会进行切分,以后就是每达到10G切分一次,切分完成后,会进行负载均衡,均衡到其他regionserver预分区自定义rowke…...
图的宽度优先深度优先遍历
图常见的遍历方式有两种,一种是宽度优先遍历,一种是深度优先遍历。 宽度优先遍历 宽度优先遍历和之前介绍的二叉树的层级遍历类似,主要也是利用Queue来完成层级的遍历,除此之外,因为图中很可能有环,所以还…...
redis Set类型命令
Redis中的Set是一种无序、不重复的集合数据结构,它提供了一系列的操作命令用于对Set进行添加、删除和查找等操作。以下是Redis中Set类型常见的一些命令: SADD key member [member …]:将一个或多个成员添加到指定的集合中。 示例:…...
Netty框架自带类DefaultEventExecutorGroup的作用,用来做业务的并发
一、DefaultEventExecutorGroup的用途 DefaultEventExecutorGroup 是 Netty 框架中的一个类,用于管理和调度事件处理器(EventExecutor)的组。在 Netty 中,事件处理是通过多线程来完成的,EventExecutor 是处理事件的基…...
TCP的四次挥手与TCP状态转换
文章目录 四次挥手场景步骤TCP状态转换 四次挥手场景 TCP客户端与服务器断开连接的时候,在程序中使用close()函数,会使用TCP协议四次挥手。 客户端和服务端都可以主动发起。 因TCP连接时候是双向的,所以断开的时候也是双向的。 步骤 三次…...
【网络编程】实现一个简单多线程版本TCP服务器(附源码)
TCP多线程 🌵预备知识🎄 Accept函数🌲字节序转换函数🌳listen函数 🌴代码🌱Log.hpp🌿Makefile☘️TCPClient.cc🍀TCPServer.cc🎍 util.hpp 🌵预备知识 &…...
centos离线部署docker
有些内部环境需要离线部署,以下做一些备忘。 环境:centos7.9 准备文件: docker-20.10.9.tgz,下载地址 https://download.docker.com/linux/static/stable/x86_64/docker.service,内容见下文daemon.json,内…...
ffmpeg使用滤镜对视频进行处理播放
一、前言 在现代的多媒体处理中,视频和音频滤镜起着至关重要的作用。可以帮助开发者对视频和音频进行各种处理,如色彩校正、尺寸调整、去噪、特效添加等。而FFmpeg作为一个功能强大的开源多媒体框架,提供了丰富的滤镜库,使我们能够轻松地对多媒体文件进行处理和转换。 本…...
Ansible Handlers模块详解,深入理解Ansible Handlers 自动化中的关键组件
深入理解Ansible Handlers 自动化中的关键组件 在现代的IT环境中,自动化已经成为提高效率和减少错误的关键。Ansible作为一款流行的自动化工具,通过使用Playbooks来定义和执行任务。而Handlers作为Ansible的组件之一,在自动化过程中发挥着重要…...
threejs点击模型实现模型边缘高亮的选中效果--更改后提高帧率
先来个效果图 之前写的那个稍微有点问题,帧率只有30,参照官方代码修改后,帧率可以达到50了,在不全屏的状态下,帧率60 1.首先需要导入库 // 用于模型边缘高亮 import { EffectComposer } from "three/examples/js…...
RocketMQ 主备自动切换模式部署
目录 主备自动切换模式部署 Controller 部署 Controller 嵌入 NameServer 部署 Controller 独立部署 Broker 部署 兼容性 升级注意事项 主备自动切换模式部署 该文档主要介绍如何部署支持自动主从切换的 RocketMQ 集群,其架构如上图所示ÿ…...
【MySQL】select相关
文章目录 迭代器distinct 关键字limit offset 关键字order by 列名 asc\descselect语句的执行顺序几点注意 迭代器 指向第一个元素 使用hasNext()进行判断后才进行取元素 resultSet:指向第一个元素前一个 distinct 关键字 去除一列中的重复元素 可以进行多行的去重…...
在Python中应用RSA算法实现图像加密:基于Jupyter环境的详细步骤和示例代码
一、引言 在当今的数字化社会中,信息安全问题备受关注。随着数字图像在生活中的应用越来越广泛,图像的安全性和隐私性也成为人们关心的焦点。如何在网络上安全地传输和存储图像已经成为一项重要的挑战。RSA(Rivest-Shamir-Adleman)算法作为一种被广泛应用的公钥密码体系,…...
Prometheus Blackbox Exporter 的 HTTP 探测指标中各个阶段的时间统计信息
在 Prometheus Blackbox Exporter 的 HTTP 探测指标中,probe_http_duration_seconds 指标包含各个阶段的时间统计信息。这些阶段代表了 HTTP 探测的不同阶段和指标。以下是各个阶段的含义: phase"dns_lookup":这是指进行 DNS 查找…...
数据结构之时间复杂度-空间复杂度
大家好,我是深鱼~ 目录 1.数据结构前言 1.1什么是数据结构 1.2什么是算法 1.3数据结构和算法的重要性 1.4如何学好数据结构和算法 2.算法的效率 3.时间复杂度 3.1时间复杂度的概念 3.2大O的渐进表示法 【实例1】:双重循环的时间复杂度…...
新一代构建工具 maven-mvnd
新一代构建工具 maven-mvnd mvnd的前世今生下载安装 mvndIDEA集成 mvnd的前世今生 maven 作为一代经典的构建工具,流行了很多年,知道现在依然是大部分Java项目的构建工具的首选;但随着项目复杂度提高,代码量及依赖库的增多使得ma…...
构建Docker容器监控系统(2)(Cadvisor +Prometheus+Grafana)
Cadvisor产品简介 Cadvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行Cadvisor用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示。 接着上一篇来继续 部署Cadvisor 被监控主机上部署Cadvisor容器…...
Unity地形草刷不上?根源是单顶点Mesh硬限制
1. 问题不是“刷不上去”,而是Unity地形系统对Mesh草的底层限制逻辑被误解了“Unity地形使用Mesh网格刷草刷不上”——这句话在Unity社区里每年至少被重复提问3000次以上。我第一次遇到它是在2019年做一款开放世界生存游戏时,美术同事把精心建模的蒲公英…...
TikTok广告账号被封怎么解决?2026年防封号完整攻略
做TikTok广告投放,最让人头疼的事情是什么?账号被封。前一秒还在跑量,后一秒突然提示账号异常,所有广告计划全部暂停,预算打水漂,客户推广计划全乱。这种经历,做过TikTok广告投放的卖家应该都不…...
数据安全合规实战:等保2.0和GDPR要求下的文件加密配置清单
从“过等保”到“过审计”,一份可直接照抄的配置模板又到了每年合规审计季。去年我们公司同时面临等保2.0三级复测和欧盟客户要求的GDPR合规审查,其中文件加密是两者共同的重点项。我们以天锐绿盾为基础,整理了一套加密合规配置清单ÿ…...
数据结构——带懒标记的线段树
一、什么是线段树?线段树是一种二叉树数据结构,用于高效地处理区间查询和区间更新操作。核心思想:将数组分成若干个区间(线段),每个节点代表一个区间,通过合并子节点的信息来得到父节点的信息。…...
别再手动Cherry-pick了!用IDEA的Squash功能,3步合并Git提交历史
告别零碎Commit:IDEA交互式变基实战指南 在团队协作开发中,每个开发者都经历过这样的场景:为了修复一个看似简单的Bug,你在本地分支上提交了五六个"WIP"(Work in Progress)或"fix typo"…...
工业眼睛:11 老手血泪Tips + 新手避坑清单
11 老手血泪Tips + 新手避坑清单 上回聊完机器视觉给工厂安了“眼睛”,AI让它升级成“火眼金睛”,数据闭环一接,生产线直接会自己挑毛病。今天不整高大上的理论,来点真刀真枪的干货——11条老手血泪Tips(全是师傅们用命换来的教训,踩坑踩到哭),外加新手避坑清单(直接…...
yt-fts高级配置技巧:数据库路径、Chroma设置与性能优化
yt-fts高级配置技巧:数据库路径、Chroma设置与性能优化 【免费下载链接】yt-fts YouTube Full Text Search - Search all of YouTube from the command line 项目地址: https://gitcode.com/gh_mirrors/yt/yt-fts yt-fts是一款强大的YouTube全文搜索工具&…...
3分钟掌握gmpublisher:Garry‘s Mod工坊发布的终极解决方案
3分钟掌握gmpublisher:Garrys Mod工坊发布的终极解决方案 【免费下载链接】gmpublisher ⚙️ Workshop Publishing Utility for Garrys Mod, written in Rust & Svelte and powered by Tauri 项目地址: https://gitcode.com/gh_mirrors/gm/gmpublisher 还…...
基于ZYNQ与IgH的EtherCAT主站方案:软硬协同实现工业实时控制
1. 项目概述:当工业实时网络遇上可编程SoC在工业自动化领域,实时性和确定性是永恒的核心诉求。EtherCAT作为高性能的工业以太网协议,以其独特的“飞读飞写”数据处理机制和极低的通信抖动,成为了众多高精度运动控制、机器人、半导…...
article-extractor项目架构解析:模块化设计与可扩展性指南
article-extractor项目架构解析:模块化设计与可扩展性指南 【免费下载链接】article-extractor To extract main article from given URL with Node.js 项目地址: https://gitcode.com/gh_mirrors/ar/article-extractor article-extractor是一个强大的Node.j…...
