Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問題的解決方法
前言
項(xiàng)目老大說項(xiàng)目需要重構(gòu)搜索功能,決定交給我這個(gè)比較閑的人! 嗯 ???
因?yàn)橐郧暗捻?xiàng)目數(shù)據(jù)不大,都不能說不大,是很少,所有搜索采用的是MySQL中的like模糊搜索操作的,他希望我改一下;
我第一時(shí)間想到了ES,但他說沒必要用ES,等以后數(shù)據(jù)量大了再換,現(xiàn)在只是稍微多了一些數(shù)據(jù),沒必要
Ok!那我就用了MySQL自帶的全文檢索功能,因?yàn)楸疚闹饕f的還是Mybatis-Plus的問題,所以全文檢索在下面只會(huì)提到怎么使用,以及一些問題
好像說了一大堆廢話,回歸正題!
項(xiàng)目以前分頁(yè)搜索用的是PageHelper這個(gè)插件,但公司封裝的3.0框架中已經(jīng)封裝了Mybatis-Plus,所以我采用了Mybatis-Plus的分頁(yè)插件
一、問題說明
場(chǎng)景:
老師表是有4條數(shù)據(jù),每個(gè)老師對(duì)應(yīng)2個(gè)學(xué)生
使用的是兩個(gè)表聯(lián)查letf join加Mybatis的級(jí)聯(lián)查詢,一次性獲取所有數(shù)據(jù)出現(xiàn)3個(gè)問題:
1、數(shù)據(jù)總條數(shù)以及頁(yè)數(shù)不對(duì)
2、數(shù)據(jù)分頁(yè)數(shù)量不對(duì)
3、數(shù)據(jù)混亂
已下是我有問題的代碼:
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 {
/**
* 插件注冊(cè)
*
* @param paginationInnerInterceptor 分頁(yè)插件
* @return MybatisPlus攔截器
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(PaginationInnerInterceptor paginationInnerInterceptor) {
MybatisPlusInterceptor mp = new MybatisPlusInterceptor();
mp.addInnerInterceptor(paginationInnerInterceptor);
return mp;
}
//分頁(yè)插件
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor pii = new PaginationInnerInterceptor();
pii.setMaxLimit(20L);
pii.setDbType(DbType.MYSQL);
//當(dāng)超過最大頁(yè)數(shù)時(shí)不會(huì)報(bào)錯(cuò)
pii.setOverflow(true);
return pii;
}
}
3、創(chuàng)建mapper層
創(chuàng)建了一個(gè)返回實(shí)體類
TeacherVO,包括老師信息以及學(xué)生信息,以及一個(gè)傳入的參數(shù)類TeacherRequestVo
@Data
public class TeacherVO {
/**
* 跟學(xué)生表關(guān)聯(lián)的字段
*/
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> {
/**
* 獲取老師所帶班級(jí)中的所有老師及學(xué)生信息
* @param page mybatisplus自帶的page類
* @param teacherRequestVo 傳入的參數(shù)
* @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、測(cè)試一(不傳任何條件,只分頁(yè))
測(cè)試結(jié)果應(yīng)該是二條數(shù)據(jù),總數(shù)是四條
@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": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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、結(jié)果總結(jié)
1、總條數(shù)正確
2、頁(yè)數(shù)正確
3、數(shù)據(jù)不正確,返回條數(shù)不正確,應(yīng)該返回兩條數(shù)據(jù),但現(xiàn)在只返回了一條
5.2、結(jié)果分析
查看它最終指向的sql語(yǔ)句
找到在
SimpleExecutor下的doQuery方法。

總條數(shù)的sql語(yǔ)句為:
SELECT COUNT(*) AS total FROM teacher t
分頁(yè)語(yǔ)句為:
select *
from teacher t
left join student s on t.classs = s.classs LIMIT 2
拿去數(shù)據(jù)庫(kù)運(yùn)行結(jié)果為:

至此可以看出它只是獲取了同一個(gè)老師下兩個(gè)不同的學(xué)生信息;
而不是我們想象的兩個(gè)老師,分別對(duì)應(yīng)多個(gè)學(xué)生;
但總條數(shù)和條數(shù)正確
6、測(cè)試二(傳兩個(gè)表的條件)

得到的結(jié)果應(yīng)該是一個(gè)老師對(duì)應(yīng)他下面的兩個(gè)學(xué)生
總條數(shù)是1
總數(shù)是1
6.1、測(cè)試結(jié)果
{
"records": [
{
"classs": "804",
"tname": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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、結(jié)果總結(jié)
總條數(shù)不對(duì)
頁(yè)數(shù)雖然對(duì),但是那是因?yàn)槲覀兎猪?yè)的數(shù)量是2,而學(xué)生表中正好是一個(gè)老師對(duì)應(yīng)兩個(gè)學(xué)生,所以才對(duì),但只要當(dāng)一個(gè)老師對(duì)應(yīng)3個(gè)學(xué)生或者超過2的話,頁(yè)數(shù)也就不會(huì)對(duì)了,這里就不給大家測(cè)試了,大家可以自行測(cè)試一下
數(shù)據(jù)雖然看起來(lái)對(duì)的,但是跟頁(yè)數(shù)是一樣的道理,其實(shí)是錯(cuò)的
6.3、結(jié)果分析
還是查看它最終執(zhí)行的SQL語(yǔ)句:
發(fā)現(xiàn)執(zhí)行查詢總條數(shù)的SQL語(yǔ)句有問題
SELECT COUNT(*) AS total FROM teacher t LEFT JOIN student s ON t.classs = s.classs WHERE s.size <= 3 AND t.classs = '804'
二、解決
在上面的測(cè)試中發(fā)現(xiàn)兩個(gè)問題
1、數(shù)據(jù)不對(duì)
2、條數(shù)和頁(yè)數(shù)不對(duì)
1、沒條件查詢只分頁(yè)
我們修改
xxxMapper.xml中的resultMap采用級(jí)聯(lián)查詢
<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": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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、兩個(gè)表都有條件

{
"records": [
{
"classs": "804",
"tname": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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": "李誠(chéng)",
"tsex": "男",
"tbirthday": "1958-12-02 00:00:00",
"prof": "副教授",
"depart": "計(jì)算機(jī)系",
"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、結(jié)果總結(jié)
無(wú)條件時(shí)
數(shù)量正確,數(shù)據(jù)重復(fù),頁(yè)數(shù)正確
兩表都有條件時(shí):
總數(shù)不對(duì),數(shù)據(jù)重復(fù),頁(yè)數(shù)不正確
4、結(jié)果分析
查看最終sql語(yǔ)句
查詢總條數(shù)的SQL語(yǔ)句:
SELECT COUNT(*) AS total FROM teacher t LEFT JOIN student s ON t.classs = s.classs WHERE s.size <= ? AND t.classs = ?
查詢老師表的SQL語(yǔ)句:
select t.*
from teacher t
left join student s on t.classs = s.classs
WHERE s.size <= 3
and t.classs = "804" LIMIT 2
去數(shù)據(jù)庫(kù)執(zhí)行發(fā)現(xiàn)查詢老師表的sql語(yǔ)句查出兩條相同結(jié)果
其實(shí)到這里很多人都知道怎么解決了,只要去除重復(fù)的數(shù)據(jù),所有問題都可以解決,無(wú)論是用去重,還是GROUP BY都可以實(shí)現(xiàn),我下面采用GROUP BY
5、最終方案
加上
GROUP BY進(jìn)行去重,其他地方都沒改動(dòng)
<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、坑
進(jìn)行分組的字段必須是主鍵,不然會(huì)報(bào)錯(cuò)
這里就不給大家展示測(cè)試結(jié)果了,沒必要了,大家可自行測(cè)試
到這里問題完美解決
三、結(jié)束語(yǔ)
本人寫過的所有解決什么問題都是項(xiàng)目中花了超過1個(gè)多小時(shí)才解決的問題,希望這篇文章對(duì)同學(xué)們有所幫助,不喜勿噴,有任何問題都可以評(píng)論,最后送上我的兩句座右銘:
任何人都不會(huì)在意你成功的過程,只在意你成功的結(jié)果,在你沒有成功之前,切勿向別人強(qiáng)調(diào)過程;
請(qǐng)不要假裝努力,結(jié)果不會(huì)陪你演戲;
到此這篇關(guān)于Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問題的解決方法的文章就介紹到這了,更多相關(guān)Mybatis-Plus多表分頁(yè)查詢總條數(shù)不對(duì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis-Plus多表聯(lián)查的實(shí)現(xiàn)方法(動(dòng)態(tài)查詢和靜態(tài)查詢)
- mybatis-plus多表關(guān)聯(lián)查詢功能的實(shí)現(xiàn)
- springboot整合mybatis-plus實(shí)現(xiàn)多表分頁(yè)查詢的示例代碼
- springboot + mybatis-plus實(shí)現(xiàn)多表聯(lián)合查詢功能(注解方式)
- MyBatis-Plus多表聯(lián)合查詢并且分頁(yè)(3表聯(lián)合)
- 結(jié)合mybatis-plus實(shí)現(xiàn)簡(jiǎn)單不需要寫sql的多表查詢
- mybatis-plus多表查詢操作方法
相關(guān)文章
Springcloud Config配置中心使用與相關(guān)介紹
springcloud config是一個(gè)解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個(gè)部分,server端提供配置文件的存儲(chǔ)、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-09-09
在Web項(xiàng)目中手機(jī)短信驗(yàn)證碼實(shí)現(xiàn)的全過程記錄
這篇文章主要給大家介紹了關(guān)于在Web項(xiàng)目中實(shí)現(xiàn)短信驗(yàn)證碼的全過程記錄,文中通過示例代碼介紹的非常詳細(xì),在文末跟大家提供了源碼下載,需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
簡(jiǎn)單介紹Java網(wǎng)絡(luò)編程中的HTTP請(qǐng)求
這篇文章主要介紹了簡(jiǎn)單介紹Java網(wǎng)絡(luò)編程中的HTTP請(qǐng)求,需要的朋友可以參考下2015-09-09
Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的實(shí)踐指南
在 Java 開發(fā)中,許多場(chǎng)景需要訪問多個(gè)數(shù)據(jù)庫(kù),例如多租戶系統(tǒng)或讀寫分離架構(gòu),為了靈活高效地管理這些場(chǎng)景,動(dòng)態(tài)數(shù)據(jù)源切換技術(shù)應(yīng)運(yùn)而生,所以本文給大家介紹了Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的實(shí)踐指南,需要的朋友可以參考下2025-03-03
Java8中Stream使用的一個(gè)注意事項(xiàng)
最近在工作中發(fā)現(xiàn)了對(duì)于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中Stream使用過程中的一個(gè)注意事項(xiàng),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11
SpringBoot Java后端實(shí)現(xiàn)okhttp3超時(shí)設(shè)置的方法實(shí)例
Okhttp的使用沒有httpClient廣泛,網(wǎng)上關(guān)于Okhttp設(shè)置代理的方法很少,下面這篇文章主要給大家介紹了關(guān)于SpringBoot Java后端實(shí)現(xiàn)okhttp3超時(shí)設(shè)置的相關(guān)資料,需要的朋友可以參考下2021-10-10
Java8時(shí)間轉(zhuǎn)換(LocalDateTime)代碼實(shí)例
這篇文章主要介紹了java8時(shí)間轉(zhuǎn)換(LocalDateTime)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

