SpringBoot项目中PageHelper给子查询做分页

news2024/12/25 13:48:59

目录

1.起因

 2.sql改进

3.改造pagehelper

4.新的问题

方案一

方案二

方案三(终极)

5.附上pagehelper官方使用指南


1.起因

项目中有个查询非常慢,查询第一页都很慢,

sql为一张大表A left join了许多张基础数据表(小表),

select * from A
left join b on xxx
left join c on xxx
left join d on xxx
left join e on xxx
left join f on xxx
left join g on xxx
left join h on xxx
left join i on xxx
left join g on xxx
where xxx

此时的sql被pagehelper包装在最后加了limit x,x查询比较慢

 2.sql改进

其实翻页一页就10条数据,靠前的页码应该是很快的(项目中限制了只能查前10页),select * from A limit 10,10很快

于是想着改进sql,先单独查出大表分页数据后在left join其它基础数据表

select * from (
    select * from A where xxx order by xxx limit x,x
) A1
left join b on xxx
left join c on xxx
left join d on xxx
left join e on xxx
left join f on xxx
left join g on xxx
left join h on xxx
left join i on xxx
left join g on xxx

3.改造pagehelper

由于pagehelper的分页是包在整个执行sql的最外层,想要limit加在指定位置需要,我操作的数据源是mysql就需要去重写pagehelper的MySqlDialect里面的getPageSql方法,具体造作如下

编写MySqlDialectUdf类继承MySqlDialect重写getPageSql方法

package com.hsf.framework.datasource;

import com.github.pagehelper.Page;
import com.github.pagehelper.dialect.helper.MySqlDialect;
import org.apache.ibatis.cache.CacheKey;

import java.util.regex.Pattern;

/**
 * ClassName: MySqlDialectUdf
 * Description:
 * date: 2023/6/30 14:58
 *
 * @author yanglp
 * @since JDK 1.8
 */
public class MySqlDialectUdf extends MySqlDialect {
    @Override
    public String getPageSql(String sql, Page page, CacheKey pageKey) {
        Pattern compileFixed = Pattern.compile("/\\*fixed\\*/");
        String compileLimit = "/\\*limit\\*/";
        if (compileFixed.matcher(sql).find()) {//自定义分页逻辑
            if (page.getStartRow() == 0) {//第一页
                sql = sql.replaceFirst(compileLimit, " LIMIT ? ");
            } else {
                sql = sql.replaceFirst(compileLimit, " LIMIT ?, ? ");
            }
            return sql;
        }
        return super.getPageSql(sql, page, pageKey);//正常分页逻辑
    }
}

代码里面有两个重要的字符串

/*fixed*/ 代表此sql将自定义按指定位置插入limit

/*limit*/ 代表要插入limit的具体位置

匹配到自定定义分页指令则走自定义拼接,未匹配到则走正常的分页逻辑

接下来改造sql,改造完的mapper.xml查询语句为

<select id="selectMesProcessChangeList" parameterType="MesProcessChange" resultMap="MesProcessChangeResult">
        /*fixed*/
        select * (
          select * from A
        <where>
            <if test="barcode != null  and barcode != ''"> and barcode = #{barcode}</if>
            <if test="docNo != null  and docNo != ''"> and doc_no = #{docNo}</if>
            <if test="companyId != null "> and company_id = #{companyId}</if>
        </where>
        order by id desc /*limit*/ ) pc
        left join b on xxx
        left join c on xxx
        left join d on xxx
        left join e on xxx
        left join f on xxx
        left join g on xxx
        left join h on xxx
        left join i on xxx
        left join g on xxx
</select>

那么怎么生效走MySqlDialect呢,在yml文件中配置pagehelper.helperDialect

pagehelper:
  helperDialect: com.hsf.framework.datasource.MySqlDialectUdf

本来pagehelper.helperDialect是配置pagehelper的指定方言的,配置为mysql,那么解析拼接分页的时候就是走的MySqlDialect,但是我们重写了MySqlDialect,需要走我们自定义的方法,那么helperDialect就需要指定为MySqlDialectUdf的全路径名

4.新的问题

到这里如果你的项目是单一数据源且为mysql,那么如上操作就够了,如果你的项目配置了多数据源且是不同数据库类型的,那么如上配置问题就来了

我的项目是有两个数据源一个mysql一个sqlserver,如上配置之后导致sqlserver的分页语句也走的mysql的limit做分页显然不对

多数据源配置autoRuntimeDialect为true之后pagehelper允许在运行时根据多数据源自动识别对应方言的分页,做成如下配置

pagehelper:
  helperDialect: com.hsf.framework.datasource.MySqlDialectUdf
  autoRuntimeDialect: true

发现自定义的MySqlDialect并未生效,看源码发现如果设置自动选择方言autoRuntimeDialect: true之后,helperDialect属性的设置是不会生效的

public void setProperties(Properties properties) {
        this.initAutoDialectClass(properties);
        String useSqlserver2012 = properties.getProperty("useSqlserver2012");
        if (StringUtil.isNotEmpty(useSqlserver2012) && Boolean.parseBoolean(useSqlserver2012)) {
            registerDialectAlias("sqlserver", SqlServer2012Dialect.class);
            registerDialectAlias("sqlserver2008", SqlServerDialect.class);
        }

        this.initDialectAlias(properties);
        String dialect = properties.getProperty("helperDialect");
        String runtimeDialect = properties.getProperty("autoRuntimeDialect");
        if (StringUtil.isNotEmpty(runtimeDialect) && "TRUE".equalsIgnoreCase(runtimeDialect)) {
            this.autoDialect = false;
            this.properties = properties;
        } else if (StringUtil.isEmpty(dialect)) {
            this.autoDialect = true;
            this.properties = properties;
        } else {
            this.autoDialect = false;
            this.delegate = instanceDialect(dialect, properties);
        }

    }

问题又来了,既要mysql能走自定义方言又要不同类型数据源能自动切换方言该怎么办,

方案一

前面写过一篇自定义pagehelper的拦截器的

Mybatis PageHelper分页语句执行前做sql拦截并变更

用这个方案可以拦截sql做截取变换改造sql,但现在我们要使用自定义方言,放弃这个方案

方案二

下载pagehelper的源码修改原生MySqlDialect的getPageSql再打包成jar引入到我们的项目可以参考这篇文章

PageHelper-Spring-Boot-Starter 新增SUNDB数据库支持

方案三(终极)

我项目引入的是pagehelper-spring-boot-starter

<dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>1.4.5</version>
            </dependency>

继续翻看GitHub - pagehelper/pagehelper-spring-boot: pagehelper-spring-boot

看到版本更新日志 

1.2.4版本就已经支持各种类型的数据库的自定义方言实现了

pagehelper:
  dialectAlias: mysql=com.hsf.framework.datasource.MySqlDialectUdf
  autoRuntimeDialect: true
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql

如上配置,既可以实现不同数据库切换方言,又可以自定义对应数据库的自定义分页实现,完美解决

5.附上pagehelper官方使用指南

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

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

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

相关文章

安全、环保的随身“数据库”——体验希捷锦系列移动硬盘

移动硬盘不属于那种技术更新换代快、差异化明显的产品&#xff0c;因此消费者在选购时关注的点无外乎容量、价格、外观、传输速度以及数据安全等方面。希捷新推出的锦系列移动硬盘&#xff0c;就聚焦数据安全&#xff0c;同时在选材上贯彻了环保理念&#xff0c;设计方面也值得…

Linux限制用户使用特权-限制su

Linux下&#xff0c;允许普通用户通过su命令切换到root身份进行操作。 相对于直接使用root登录操作&#xff0c;这钟方法要安全些。但仍存在安全隐患。 缩小特权使用用户的范围&#xff0c;无疑是更安全的做法。 Linux提供了这样的设置。 编辑/etc/pam.d/su文件&#xff0c…

ai绘画工具有免费的吗?3款ai画图工具分享

在ai绘画工具问世之后&#xff0c;我试验了各种软件&#xff0c;有的功能太过简单&#xff0c;无法满足我对创作的要求&#xff1b;有的则要求我花费大额费用才能享受完整的功能。这让我在探索过程中一度怀疑是否真的有免费软件能够满足我的需求。 然而功夫不负有心人&#xf…

MySQL数据库——MHA高可用

MySQL数据库——MHA高可用 一、MHA概述1&#xff0e;什么是 MHA2&#xff0e;MHA 的组成3&#xff0e;MHA 的特点 二、搭建 MySQL MHA1.Master、Slave1、Slave2 节点上安装 mysql5.72&#xff0e;修改 Master、Slave1、Slave2 节点的主机名&#xff0c;添加主从mysql的映射关系…

数据结构--栈的引用--前中后缀表达式(后部分)

数据结构–栈的引用–前中后缀表达式(后部分) 中缀表达式转后缀表达式&#xff08;手算) 中缀转后缀 \color{purple}中缀转后缀 中缀转后缀的 手算方法 \color{purple}手算方法 手算方法: ①确定中缀表达式中 各个运算符的运算顺序 \color{red}各个运算符的运算顺序 各个运算符…

编程手记【2023-6-25-2023-6-30】

1、Call to ‘toArray()’ with pre-sized array argument ‘new Integer[list.size()]’ 问题&#xff1a; // 将List转为数组 List<Integer> list Arrays.asList(1,2,3,4,5,6); Integer[] array list.toArray(new Integer[list.size()]); System.out.println(Array…

《移动互联网技术》 第二章 无线网络技术: 掌握各种近距离通信的基本概念和工作原理

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

ECShop 权限管理

如何增加一个新的权限 1、配置菜单所对应的权限code admin/includes/inc_priv.php $purview[02_cost_list] cost_list; 2、配置菜单的语言 languages/zh_cn/admincommon.php $_LANG[02_cost_list] 成本明细; 3、配置权限code的语言 languages/zh_cn/admin/priv_action.p…

制作电子宣传册详细教程?掌握技巧,让你0基础也能上手

企业电子宣传册是现代企业进行品牌推广和宣传的重要手段&#xff0c;随着互联网的发展&#xff0c;越来越多的企业开始使用电子宣传册来替代传统的纸质宣传册。电子宣传册可以通过互联网&#xff0c;微信公众号等传播渠道进行发布和传播&#xff0c;可以更加快速、便捷地传递企…

碳排放预测模型 | Python实现基于LR线性回归的碳排放预测模型

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于LR线性回归的碳排放预测模型 研究内容 碳排放被认为是全球变暖的最主要原因之一。 该项目旨在提供各国碳排放未来趋势的概述以及未来十年的全球趋势预测。 其方法是分析这…

二叉树刷题总结

题单&#xff1a; 一&#xff0c;相同的树 题目&#xff1a; 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 题目接口&#xff1a; /*** Defin…

Tensorflow神经网络模型-鲜花种类识别

必应壁纸供图 Tensorflow神经网络模型-鲜花种类识别 数据集&#xff1a;https://download.csdn.net/download/weixin_53742691/87982215 导入相关依赖 import warnings import re from IPython.display import clear_output, display from tkinter import Tk, filedialog fro…

无序中的秩序之美:集合数据为编程世界增添新的维度

文章目录 集合数据简介集合数据特点常见的集合数据类型1. 列表&#xff08;List&#xff09;2. 元组&#xff08;Tuple&#xff09;3. 集合&#xff08;Set&#xff09;4. 字典&#xff08;Dictionary&#xff09; 集合数据简介 集合数据是指将多个元素组合在一起的数据结构。…

【数据库原理】MyShop 商城数据库设计(SQL server)

MyShop 商城数据库设计 项目背景定义课程设计要求概念结构设计逻辑结构设计数据结构的描述用户信息数据结构的描述地址信息数据结构的描述商品类别数据结构的描述商品数据结构的描述购物车数据结构的描述订单数据结构的描述订单项数据结构的描述 物理结构设计用户表结构地址表结…

机器视觉检测中的图像预处理方法:平滑模糊处理,锐化

一、平滑模糊处理 以Dalsa sherlock软件为例,一起来了解一下视觉检测中平滑模糊的图像处理方法。 1、观察灰度分布来描述一幅图像称为空间域,观察图像变化的频率被称为频域。 2、频域分析:低频对应区域的图像强度变化缓慢,高频对应的变化快。低通滤波器去除了图像的高频部…

【支付系统】java springboot 生成二维码,二维码中文乱码

支付系统必不可少的就是生成二维码,有时我们会需要将支付链接转换为二维码.用户通过移动设备扫描二维码调起支付. 该篇文章主要使用的是hutool自带的二维码生成功能. 1. 引入依赖(hutool 可以按需引入这里就直接使用all了) <dependency><groupId>com.google.zxing&…

conda环境里用不了电脑系统环境里的应用ffmpeg;ffmpeg调用本地windows麦克风读取

1、 ffmpegzai conda环境里执行不了&#xff0c;在系统可以运行 import ffmpegstream ffmpeg.input(rD:\sound\222.mp4) stream ffmpeg.filter(stream, fps, fps25, roundup) stream ffmpeg.output(stream, rD:\sound\dummy2.mp4) ffmpeg.run(stream)会报错&#xff1a; Fi…

分布式配置 Config

一、Config 简介 1、Config的组成 Server&#xff1a;分布式配置中心&#xff0c;是独立运行的微服务应用&#xff0c;连接配置仓库(Git、SVN、本地化文件等)并为客户端提供获取配置信息、加密信息和解密信息的访问接口。Client&#xff1a;各个微服务&#xff0c;通过 Serve…

ChatGLM2-6B发布,位居C-Eval榜首

ChatGLM-6B自2023年3月发布以来&#xff0c;就已经爆火&#xff0c;如今6月25日&#xff0c;清华二代发布&#xff08;ChatGLM2-6B&#xff09;&#xff0c;位居C-Eval榜单的榜首&#xff01; 项目地址&#xff1a;https://github.com/THUDM/ChatGLM2-6B HuggingFace&#xf…

java开发必备技能之Java泛型

简介 泛型的优点 1、泛型的本质是为了参数化类型&#xff0c;也就是在在不创建新的类型的情况下&#xff0c;通过泛型指定的不同类型来控制形参具体限制的类型&#xff0c;很明显这种方法提高了代码的复用性(比如List因为使用泛型可以添加任意类型的对象&#xff0c;而不需要…