彻底解决ruoyi分页后总数错误的问题

2023-09-15 09:35:35

问题描述

最近时不时的发现用户列表出来的数据只有24条,但是总记录数却有58条,很奇怪。各种百度查询,都是什么修改查询分页改代码,尝试后发现还是没有效果,经过各种验证发现就是SQL语句错误。

如果非要说是SQL语句没有问题,查询出来的数据是正确的,如果基于这个事实去讲那确实没有错,错的是你建表的字段类型不一致,这是本质错误。举个例子,你的主表user中有一个dept_id的字段,而这个字段是varchar(200),但是你的dept表的id确实bigint的类型,这个时候就会出现你用具体的字段去查询是正确的结果数据,但是用count(*) 去查询就是错误的记录数。

解决方法前提

先把PageUtils.java替换成和我一样的。避免出现其它的幺蛾子。

package com.ruoyi.common.utils;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.utils.sql.SqlUtil;

import java.util.List;

/**
 * 分页工具类
 *
 * @author ruoyi
 */
public class PageUtils extends PageHelper {

    private static Page page;
    /**
     * 设置请求分页数据
     */
    public static void startPage() {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
            Boolean reasonable = pageDomain.getReasonable();
            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
        }
    }


    public static TableDataInfo getDataTable(List<?> list) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(page.getTotal());
        return rspData;
    }
}

解决方法1

把两张表的字段类型对应成一样的。如果有一个是bigint,有一个是varchar要么都统一修改为varchar要么统一修改为bigint。

解决访问2

字段不用修改,修改SQL语句,把bigint的字段转换一下,如下

// 错误的写法
select count(0)
        from user u
        left join dept d on d.id=u.dept_id
        where 1=1
        and u.is_deleted = 0

// 正确的写法
select count(0)
        from user u
        left join dept d on concat(d.id,'')=u.dept_id
        where 1=1
        and u.is_deleted = 0

// 正确的写法
select count(0)
        from user u
        left join dept d on cast( d.id AS CHAR )=u.dept_id
        where 1=1
        and u.is_deleted = 0

警告

切记,不要让没有经验的人去设计表结构,我这次就是为了100%兼容V1版本的设计,用ruoyi框架去做的倾斜匹配,导致各种问题。

------------------------------华丽的分割线--------

无用解决方案

以下都是没有用的解决方案,大家不用看了,修改你的SQL语句去吧。下面的都是凑字数的。

分页插件如何手写count查询支持

增加countSuffix count 查询后缀配置参数,该参数是针对PageInterceptor配置的,默认值为_COUNT

分页插件会优先通过当前查询的msId + countSuffix查找手写的分页查询。

如果存在就使用手写的count查询,如果不存在,仍然使用之前的方式自动创建count查询。

例如,如果存在下面两个查询:

<select id="selectLeftjoin" resultType="com.github.pagehelper.model.User">
    select a.id,b.name,a.py from user a
    left join user b on a.id = b.id
    order by a.id
</select>

<select id="selectLeftjoin_COUNT" resultType="Long">
    select count(distinct a.id) from user a
    left join user b on a.id = b.id
</select>

上面的countSuffix使用的默认值_COUNT,分页插件会自动获取到selectLeftjoin_COUNT查询,这个查询需要自己保证结果数正确。

返回值的类型必须是resultType="Long",入参使用的和selectLeftjoin查询相同的参数,所以在SQL中要按照selectLeftjoin的入参来使用。

因为selectLeftjoin_COUNT方法是自动调用的,所以不需要在接口提供相应的方法,如果需要单独调用,也可以提供。

如何处理Long类型精度丢失问题

当字段实体类为Long类型且值超过前端js显示的长度范围时会导致前端回显错误,解决方案如下

1、使用JsonSerialize注解序列化的时候把Long自动转为String(针对单个属性)

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

@JsonSerialize(using = ToStringSerializer.class)
private Long xxx;

2、添加JacksonConfig配置全局序列化(针对所有属性)

package com.ruoyi.framework.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

/**
 * Jackson配置
 * 
 * @author ruoyi
 *
 */
@Configuration
public class JacksonConfig
{
    @Bean
    public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter()
    {
        final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        final ObjectMapper objectMapper = builder.build();
        SimpleModule simpleModule = new SimpleModule();
        // Long 转为 String 防止 js 丢失精度
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        // 忽略 transient 关键词属性
        objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
        // 时区设置
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        return new MappingJackson2HttpMessageConverter(objectMapper);
    }
}
更多推荐

分布式架构和微服务架构的区别

1、含义不同微服务架构是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中。分布式系统是若干独立计算机的集合,这些计算机对用户来说就像单个相关系统。2、概念不同微服务架构是设计层面的东西,一般考虑如何将系统从逻辑上进行拆分,也就是垂直拆分。分布式架构是部署层面的东西,即强调物理层面的组成,即系统

操作系统备考学习 day5(2.2.5 - 2.3.1)

操作系统备考学习day5第二章进程与线程2.2处理机调度2.2.5调度算法先来先服务(FCFS)短作业优先(SJF)高响应比优先(HRRN)时间片轮转(RR)优先级调度算法多级反馈队列调度算法多级队列调度算法2.3同步与互斥2.3.1同步与互斥的基本概念第二章进程与线程2.2处理机调度2.2.5调度算法先来先服务(FC

网络安全日报 2023年09月21日

1、研究人员披露基于ERMAC木马的Hook家族银行木马https://research.nccgroup.com/2023/09/11/from-ermac-to-hook-investigating-the-technical-differences-between-two-android-malware-vari

卷积神经网络实现咖啡豆分类 - P7

🍨本文为🔗365天深度学习训练营中的学习记录博客🍖原作者:K同学啊|接辅导、项目定制🚀文章来源:K同学的学习圈子目录环境步骤环境设置包引用全局设备对象数据准备查看图像的信息制作数据集模型设计手动搭建的vgg16网络精简后的咖啡豆识别网络模型训练编写训练函数编写测试函数开始训练展示训练过程模型效果展示总结与心得体

四、二叉树-上(Binary tree)

文章目录一、算法核心思想二、算法模型(一)回溯1.[104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)(1)思路(2)代码(3)复杂度分析2.[144.二叉树的前序遍历](https://leetcode.cn/proble

基础组件(线程池、内存池、异步请求池、Mysql连接池)

文章目录1、概述2、线程池2、异步请求池3、内存池1、概述池化技术,减少了资源创建次数,提高了程序响应性能,特别是在高并发场景下,当程序7*24小时运行,创建资源可能会出现耗时较长和失败等问题,池化技术,主要是程序初始化之前创建多个可用连接,集中管理起来,后续直接使用,使用完并归还。2、线程池线程池主要解决问题:1、解

碳当量及相关指数

声明本文是学习GB-T713.1-2023承压设备用钢板和钢带第1部分:一般要求.而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们1范围本文件规定了承压设备用钢板和钢带的牌号表示方法、订货内容、尺寸、外形、重量、技术要求、检验规则、试验方法、包装、标志及质量证明书。本文件适用于锅炉、压力容器、压力管

ardupilot开发 --- 避障篇

避障的类型空中防碰撞ADSB,主要是防止与其他飞行器的碰撞;避障,防止与天花板地板障碍物的碰撞;实现避障必要的传感器ADSBreceiversRangefindersorProximitySensorsorRealsenseDepthCameraADSBhttps://ardupilot.org/copter/docs

基于微信小程序的语言课学习系统的设计与实现(源码+lw+部署文档+讲解等)

前言💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗👇🏻精彩专栏推荐订阅👇🏻2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选

PT@古典概型@等概率模型

文章目录abstract等可能概型(古典概型)🎈古典型概率公式基本性质导出性质例抽样方式放回抽样不放回抽样mmm次取求不放回和一次性取mmm个球例:取色球和古典概型古典概型经典问题放球问题两人同一天生日问题超几何分布概型整除取数问题抽签问题取最大号球问题@错位相减分组分配问题古典概型假设条件和实际推断原则其他古典概型

共享WiFi贴项目怎么实施与运营,微火为你提供高效解答!

共享WiFi贴是一项有前景的商业项目,不仅可以满足用户对网络的需求,还可以为创业者带来盈利的机会。那么,我们来看看如何有效地开展共享WiFi贴项目。最重要的是选择合适的位置。共享WiFi贴项目的成功与否很大程度上取决于位置选择。优先选择人流量较大、需求旺盛的地方,如商业区、写字楼、学校、咖啡馆等。通过深入了解目标用户群

热文推荐