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容器…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
