Mybatis-Plus或PageHelper多表分页查询总条数不对问题的解决方法

目录
  • 前言
  • 一、问题说明
    • 1、引入依赖
    • 2、Mybatis-Plus配置
    • 3、创建mapper层
    • 4、编写xxxMapper.xml文件
    • 5、测试一(不传任何条件,只分页)
      • 5.1、结果总结
      • 5.2、结果分析
    • 6、测试二(传两个表的条件)
      • 6.1、测试结果
      • 6.2、结果总结
      • 6.3、结果分析
  • 二、解决
    • 1、没条件查询只分页
    • 2、两个表都有条件
    • 3、结果总结
    • 4、结果分析
    • 5、最终方案
      • 5.1、坑
  • 三、结束语

前言

项目老大说项目需要重构搜索功能,决定交给我这个比较闲的人! 嗯 ???

因为以前的项目数据不大,都不能说不大,是很少,所有搜索采用的是MySQL中的like模糊搜索操作的,他希望我改一下;

我第一时间想到了ES,但他说没必要用ES,等以后数据量大了再换,现在只是稍微多了一些数据,没必要

Ok!那我就用了MySQL自带的全文检索功能,因为本文主要说的还是Mybatis-Plus的问题,所以全文检索在下面只会提到怎么使用,以及一些问题

好像说了一大堆废话,回归正题!

项目以前分页搜索用的是PageHelper这个插件,但公司封装的3.0框架中已经封装了Mybatis-Plus,所以我采用了Mybatis-Plus的分页插件

一、问题说明

场景:

老师表是有4条数据,每个老师对应2个学生

使用的是两个表联查letf joinMybatis的级联查询,一次性获取所有数据出现3个问题:

1、数据总条数以及页数不对

2、数据分页数量不对

3、数据混乱

已下是我有问题的代码:

1、引入依赖

版本选择尽量3.4+

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

2、Mybatis-Plus配置

@Configuration
public class MybatisPlusConfig {

    /**
     * 插件注册
     *
     * @param paginationInnerInterceptor 分页插件
     * @return MybatisPlus拦截器
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(PaginationInnerInterceptor paginationInnerInterceptor) {
        MybatisPlusInterceptor mp = new MybatisPlusInterceptor();
        mp.addInnerInterceptor(paginationInnerInterceptor);
        return mp;
    }

    //分页插件
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        PaginationInnerInterceptor pii = new PaginationInnerInterceptor();
        pii.setMaxLimit(20L);
        pii.setDbType(DbType.MYSQL);
        //当超过最大页数时不会报错
        pii.setOverflow(true);
        return pii;
    }
}

3、创建mapper层

创建了一个返回实体类TeacherVO,包括老师信息以及学生信息,以及一个传入的参数类TeacherRequestVo

@Data
public class TeacherVO {
     /**
     * 跟学生表关联的字段
     */
    private String classs;
    private String tname;
    private String tsex;
    private Date tbirthday;
    private String prof;
    private String depart;
    private List<Student> student;
}
@Data
public class TeacherRequestVo {
    private String classs;
    private String tname;
    private String sname;
}
public interface TeacherMapper extends BaseMapper<Teacher> {
    /**
     * 获取老师所带班级中的所有老师及学生信息
     * @param page mybatisplus自带的page类
     * @param teacherRequestVo 传入的参数
     * @return
     */
    Page<TeacherVO> getAll(Page<TeacherVO> page, TeacherRequestVo teacherRequestVo);
}

4、编写xxxMapper.xml文件

<resultMap id="GetAllMap" type="com.qjj.demo.entity.vo.TeacherVO">
    <!--@mbg.generated-->
    <!--@Table teacher-->
    <result column="classs" jdbcType="VARCHAR" property="classs"/>
    <result column="Tname" jdbcType="VARCHAR" property="tname"/>
    <result column="Tsex" jdbcType="VARCHAR" property="tsex"/>
    <result column="Tbirthday" jdbcType="TIMESTAMP" property="tbirthday"/>
    <result column="Prof" jdbcType="VARCHAR" property="prof"/>
    <result column="Depart" jdbcType="VARCHAR" property="depart"/>
    <collection property="student"
                ofType="com.qjj.demo.entity.Student"
                resultMap="com.qjj.consumer.mapper.StudentMapper.BaseResultMap"/>
</resultMap>

<select id="getAll" resultMap="GetAllMap">
    select *
    from teacher t
    left join student s on t.classs = s.classs
    <where>
        <if test="param2.size != null">
            and s.size <![CDATA[ <= ]]> #{param2.size}
        </if>
        <if test="param2.classs != null and param2.classs != ''">
            and t.classs = #{param2.classs}
        </if>
        <if test="param2.sname != null and param2.sname != ''">
            and s.Sname = #{param2.sname}
        </if>
        <if test="param2.tname != null and param2.tname != ''">
            and t.Tname = #{param2.tname}
        </if>
    </where>
</select>

5、测试一(不传任何条件,只分页)

测试结果应该是二条数据,总数是四条

@RestController
@RequestMapping("/demo")
public class DemoController {

    @Resource
    private TeacherMapper teacherMapper;

    @PostMapping("/test3")
    public Page<TeacherVO> getAll(TeacherRequestVo teacherRequestVo) {
        Page<TeacherVO> teacherVOPage = new Page<>(1, 2);
        return teacherMapper.getAll(teacherVOPage, teacherRequestVo);
    }

}

{
    "records": [
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null
                }
            ]
        }
    ],
    "total": 4,
    "size": 2,
    "current": 1,
    "orders": [],
    "optimizeCountSql": true,
    "searchCount": true,
    "countId": null,
    "maxLimit": null,
    "pages": 2
}

5.1、结果总结

1、总条数正确

2、页数正确

3、数据不正确,返回条数不正确,应该返回两条数据,但现在只返回了一条

5.2、结果分析

查看它最终指向的sql语句

找到在SimpleExecutor下的doQuery方法。

总条数的sql语句为:

SELECT COUNT(*) AS total FROM teacher t

分页语句为:

select *
   from teacher t
       left join student s on t.classs = s.classs LIMIT 2

拿去数据库运行结果为:

至此可以看出它只是获取了同一个老师下两个不同的学生信息

而不是我们想象的两个老师,分别对应多个学生;

但总条数和条数正确

6、测试二(传两个表的条件)

得到的结果应该是一个老师对应他下面的两个学生

总条数是1

总数是1

6.1、测试结果

{
    "records": [
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null,
                    "size": 1
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null,
                    "size": 2
                }
            ]
        }
    ],
    "total": 2,
    "size": 2,
    "current": 1,
    "orders": [],
    "optimizeCountSql": true,
    "searchCount": true,
    "countId": null,
    "maxLimit": null,
    "pages": 1
}

6.2、结果总结

总条数不对

页数虽然对,但是那是因为我们分页的数量是2,而学生表中正好是一个老师对应两个学生,所以才对,但只要当一个老师对应3个学生或者超过2的话,页数也就不会对了,这里就不给大家测试了,大家可以自行测试一下

数据虽然看起来对的,但是跟页数是一样的道理,其实是错的

6.3、结果分析

还是查看它最终执行的SQL语句:

发现执行查询总条数的SQL语句有问题

SELECT COUNT(*) AS total FROM teacher t LEFT JOIN student s ON t.classs = s.classs WHERE s.size <= 3 AND t.classs = '804'

二、解决

在上面的测试中发现两个问题

1、数据不对

2、条数和页数不对

1、没条件查询只分页

我们修改xxxMapper.xml中的resultMap采用级联查询

  <resultMap id="GetAllMap" type="com.qjj.demo.entity.vo.TeacherVO">
        <!--@mbg.generated-->
        <!--@Table teacher-->
        <result column="classs" jdbcType="VARCHAR" property="classs"/>
        <result column="Tname" jdbcType="VARCHAR" property="tname"/>
        <result column="Tsex" jdbcType="VARCHAR" property="tsex"/>
        <result column="Tbirthday" jdbcType="TIMESTAMP" property="tbirthday"/>
        <result column="Prof" jdbcType="VARCHAR" property="prof"/>
        <result column="Depart" jdbcType="VARCHAR" property="depart"/>
        <collection property="student"
                    ofType="com.qjj.demo.entity.Student1"
                    column="classs"
                    select="getStudent"/>
    </resultMap>
    <select id="getAll" resultMap="GetAllMap">
        select t.*
        from teacher t
                     left join student s on t.classs = s.classs
        <where>
            <if test="param2.size != null">
                and s.size <![CDATA[ <= ]]> #{param2.size}
            </if>
            <if test="param2.classs != null and param2.classs != ''">
                and t.classs = #{param2.classs}
            </if>
            <if test="param2.sname != null and param2.sname != ''">
                and s.Sname = #{param2.sname}
            </if>
            <if test="param2.tname != null and param2.tname != ''">
                and t.Tname = #{param2.tname}
            </if>
        </where>
    </select>

    <select id="getStudent" resultMap="com.qjj.demo.mapper.Student1Mapper.BaseResultMap">
        select *
        from student
        where classs = #{classs}
    </select>

{
    "records": [
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null,
                    "size": 1
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null,
                    "size": 2
                }
            ]
        },
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null,
                    "size": 1
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null,
                    "size": 2
                }
            ]
        }
    ],
    "total": 4,
    "size": 2,
    "current": 1,
    "orders": [],
    "optimizeCountSql": true,
    "searchCount": true,
    "countId": null,
    "maxLimit": null,
    "pages": 2
}

2、两个表都有条件

{
    "records": [
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null,
                    "size": 1
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null,
                    "size": 2
                }
            ]
        },
        {
            "classs": "804",
            "tname": "李诚",
            "tsex": "男",
            "tbirthday": "1958-12-02 00:00:00",
            "prof": "副教授",
            "depart": "计算机系",
            "student": [
                {
                    "sno": "108",
                    "sname": "丘东",
                    "ssex": "男",
                    "sbirthday": "1977-09-01 00:00:00",
                    "classs": null,
                    "size": 1
                },
                {
                    "sno": "105",
                    "sname": "匡明",
                    "ssex": "男",
                    "sbirthday": "1975-10-02 00:00:00",
                    "classs": null,
                    "size": 2
                }
            ]
        }
    ],
    "total": 2,
    "size": 2,
    "current": 1,
    "orders": [],
    "optimizeCountSql": true,
    "searchCount": true,
    "countId": null,
    "maxLimit": null,
    "pages": 1
}

3、结果总结

无条件时

数量正确,数据重复,页数正确

两表都有条件时:

总数不对,数据重复,页数不正确

4、结果分析

查看最终sql语句

查询总条数的SQL语句:

SELECT COUNT(*) AS total FROM teacher t LEFT JOIN student s ON t.classs = s.classs WHERE s.size <= ? AND t.classs = ?

查询老师表的SQL语句:

  select t.*
        from teacher t
              left join student s on t.classs = s.classs
        WHERE s.size  <= 3
        and t.classs = "804" LIMIT 2

去数据库执行发现查询老师表的sql语句查出两条相同结果

其实到这里很多人都知道怎么解决了,只要去除重复的数据,所有问题都可以解决,无论是用去重,还是GROUP BY都可以实现,我下面采用GROUP BY

5、最终方案

加上GROUP BY进行去重,其他地方都没改动

 <select id="getAll" resultMap="GetAllMap">
        select t.classs,
               t.Tname,
               t.Tsex,
               t.Tbirthday,
               t.Prof,
               t.Depart
        from teacher t
                     left join student s on t.classs = s.classs
        <where>
            <if test="param2.size != null">
                and s.size <![CDATA[ <= ]]> #{param2.size}
            </if>
            <if test="param2.classs != null and param2.classs != ''">
                and t.classs = #{param2.classs}
            </if>
            <if test="param2.sname != null and param2.sname != ''">
                and s.Sname = #{param2.sname}
            </if>
            <if test="param2.tname != null and param2.tname != ''">
                and t.Tname = #{param2.tname}
            </if>
        </where>
        GROUP BY t.classs
    </select>

5.1、坑

进行分组的字段必须是主键,不然会报错

这里就不给大家展示测试结果了,没必要了,大家可自行测试

到这里问题完美解决

三、结束语

本人写过的所有解决什么问题都是项目中花了超过1个多小时才解决的问题,希望这篇文章对同学们有所帮助,不喜勿喷,有任何问题都可以评论,最后送上我的两句座右铭:

任何人都不会在意你成功的过程,只在意你成功的结果,在你没有成功之前,切勿向别人强调过程;

请不要假装努力,结果不会陪你演戏;

到此这篇关于Mybatis-Plus或PageHelper多表分页查询总条数不对问题的解决方法的文章就介绍到这了,更多相关Mybatis-Plus多表分页查询总条数不对内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MyBatis-Plus 分页查询以及自定义sql分页的实现

    一.引言 分页查询每个人程序猿几乎都使用过,但是有部分同学不懂什么是物理分页和逻辑分页. 物理分页:相当于执行了limit分页语句,返回部分数据.物理分页只返回部分数据占用内存小,能够获取数据库最新的状态,实施性比较强,一般适用于数据量比较大,数据更新比较频繁的场景. 逻辑分页:一次性把全部的数据取出来,通过程序进行筛选数据.如果数据量大的情况下会消耗大量的内存,由于逻辑分页只需要读取数据库一次,不能获取数据库最新状态,实施性比较差,适用于数据量小,数据稳定的场合. 那么MP中的物理分页怎么实现

  • 完美解决MybatisPlus插件分页查询不起作用总是查询全部数据问题

    问题描述: 在使用mybatisplus插件进行分页查询时分页参数不起作用,总是查出来全部数据. 原因分析: 查看打印的sql日志发现sql后面并没有limit条件,怀疑是缺少配置. 解决方案: 查阅资料通过添加配置类MybatisPlusConfig解决问题: @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ return new

  • Mybatis利用分页插件PageHelper快速实现分页查询

    目录 前言 首先创建一个Maven项目 数据库中创建一张表 设置Mybatis配置文件 编写pojo实体类和mapper接口和mapper映射文件 创建测试类 总结 前言 Mybatis算是对数据库操作的利器了.但是在处理分页的时候,Mybatis并没有什么特别的方法,一般需要自己去写limit子句实现,成本较高.好在有国内开发者写了一个PageHelper插件,可以帮助我们快速实现分页查询. 官网地址 首先创建一个Maven项目 导入相关依赖: <!-- 依赖列表--> <depend

  • 解决mybatis plus 一对多分页查询问题

    最近用mybatis plus做项目,单表的增删改查都正常,做到 1对多表的分页时,用resultMap返回的时候发现返回的记录和总数对不上 返回的记录是 一 表的,二返回的总数是 多 表 查了一下,这个或者是PLUS的bug 大概的解决办法如下图:用collection,传参用column,我这里用了一个小技巧, 把外面传入的参数,作为主表的column传入到从表. 这里没找到其他方法,有其他方法可以评论告诉我 补充知识:解决Mybatis-plus利用collection查询一对多分页数据的

  • Mybatis分页查询的实现(Rowbounds和PageHelper)

    我们实现查询除了 @org.junit.Test public void test02(){ SqlSession session = MybatisUtil.getSession(); UserDao mapper = session.getMapper(UserDao.class); List<User> allUser = mapper.getAllUser(); session.close(); for (User user : allUser) { System.out.printl

  • MyBatis如何使用PageHelper实现分页查询

    目录 使用PageHelper实现分页查询 1.创建数据表 2.创建项目 2.1 创建实体类(Entity层) 2.2 数据库映射层(Mapper层) 3.运行测试 MyBatis PageHelper的使用 1.引入pagehelper的jar包 2.在mybatis的配置文件中配置拦截(也可以在spring配置文件中配置) 3.代码中如何实现 4.注意事项 分页不安全的情况 使用PageHelper实现分页查询 [实例]MyBatis使用PageHelper实现分页查询,并显示分页信息.执行

  • ssm框架+PageHelper插件实现分页查询功能

    通过搭建ssm框架,然后通过mybatis的分页插件pagehelp进行分页查询. 源码:https://gitee.com/smfx1314/pagehelper 看一下项目结构: 首先创建一个maven工程,pom中引入相关jar包 <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId&

  • SpringBoot整合PageHelper实现分页查询功能详解

    前言 本文介绍的是MyBatis 分页插件 PageHelper,如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件.分页插件支持任何复杂的单表.多表分页. 官方文档:https://pagehelper.github.io/ 项目地址:https://github.com/pagehelper/Mybatis-PageHelper 使用方法 导入依赖 在中央仓库sonatype中搜索 pageHelper,找到 pagehelper-spring-boot-star

  • Mybatis-Plus或PageHelper多表分页查询总条数不对问题的解决方法

    目录 前言 一.问题说明 1.引入依赖 2.Mybatis-Plus配置 3.创建mapper层 4.编写xxxMapper.xml文件 5.测试一(不传任何条件,只分页) 5.1.结果总结 5.2.结果分析 6.测试二(传两个表的条件) 6.1.测试结果 6.2.结果总结 6.3.结果分析 二.解决 1.没条件查询只分页 2.两个表都有条件 3.结果总结 4.结果分析 5.最终方案 5.1.坑 三.结束语 前言 项目老大说项目需要重构搜索功能,决定交给我这个比较闲的人! 嗯 ??? 因为以前的

  • MySQL优化总结-查询总条数

    1.COUNT(*)和COUNT(COL) COUNT(*)通常是对主键进行索引扫描,而COUNT(COL)就不一定了,另外前者是统计表中的所有符合的纪录总数,而后者是计算表中所有符合的COL的纪录数.还有有区别的. 优化总结,对于MyISAM表来说: 1.任何情况下SELECT COUNT(*) FROM tablename是最优选择: 2.尽量减少SELECT COUNT(*) FROMtablename WHERE COL = 'value' 这种查询: 3.杜绝SELECT COUNT(

  • Django分页查询并返回jsons数据(中文乱码解决方法)

    一.引子 Django 分页查询并返回 json ,需要将返回的 queryset 序列化, demo 如下: # coding=UTF-8 import os from django.core import serializers from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from django.shortcuts import render from django.http import

  • mybatis-plus返回查询总记录数方式

    目录 mybatis-plus返回查询总记录数 mybatis-plus分页查询,总条数为零的解决 mybatis-plus返回查询总记录数 mp框架提供了selectCount方法,来查询总记录数: 需求: 查找薪水大于3500 名字里有“小”的 员工的个数 sql实现: select count(*) from t_employee where salary>3500 and name like '%小%' 代码实现: @Test public void selectCountByQuery

  • MyBatis Plus 实现多表分页查询功能的示例代码

    在Mybatis Plus 中,虽然IService 接口帮我们定义了很多常用的方法,但这些都是 T 对象有用,如果涉及到 多表的查询,还是需要自定义Vo 对象和自己编写sql 语句,Mybatis Plus提供了一个Page 对象,查询是需要设置其中的 size 字段 和 current 字段的值 一.分页配置 可以直接使用selectPage这样的分页,但返回的数据确实是分页后的数据,但在控制台打印的SQL语句其实并没有真正的物理分页,而是通过缓存来获得全部数据中再进行的分页,这样对于大数据

  • 基于Mybatis Plus实现多表分页查询的示例代码

    注意:Mybatis Plus 3.0.7 版本才开始用[自定义sql]+[QueryWrapper],低版本不能使用,还是老实写SQL进行条件拼接 1.源码分析 在Wrapper<T>接口中就有如下方法 /** * 获取自定义SQL 简化自定义XML复杂情况 * 使用方法:自定义sql + ${ew.customSqlSegment} * 1.逻辑删除需要自己拼接条件 (之前自定义也同样) * 2.不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦) * 3.用法 ${e

  • springboot整合mybatis-plus实现多表分页查询的示例代码

    1.新建一个springboot工程 2.需要导入mybatis和mybatis-plus的依赖文件 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.1</version> </dependency> <dependency> &l

  • 基于Java 利用Mybatis实现oracle批量插入及分页查询

    目录 1.单条数据insert 2.批量数据批量insert 3.创建序列 4.oracle分页查询 前端与后端交互,分页查询 后端海量数据导出,批量查询 1.单条数据insert <!--简单SQL--> insert into userinfo (USERID, USERNAME, AGE) values(1001,'小明',20); <!--Mybatis写法1,有序列,主键是自增ID,主键是序列--> <insert id="insert" par

随机推荐