Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問(wèn)題的解決方法
前言
項(xiàng)目老大說(shuō)項(xiàng)目需要重構(gòu)搜索功能,決定交給我這個(gè)比較閑的人! 嗯 ???
因?yàn)橐郧暗捻?xiàng)目數(shù)據(jù)不大,都不能說(shuō)不大,是很少,所有搜索采用的是MySQL中的like模糊搜索操作的,他希望我改一下;
我第一時(shí)間想到了ES,但他說(shuō)沒(méi)必要用ES,等以后數(shù)據(jù)量大了再換,現(xiàn)在只是稍微多了一些數(shù)據(jù),沒(méi)必要
Ok!那我就用了MySQL自帶的全文檢索功能,因?yàn)楸疚闹饕f(shuō)的還是Mybatis-Plus的問(wèn)題,所以全文檢索在下面只會(huì)提到怎么使用,以及一些問(wèn)題
好像說(shuō)了一大堆廢話,回歸正題!
項(xiàng)目以前分頁(yè)搜索用的是PageHelper這個(gè)插件,但公司封裝的3.0框架中已經(jīng)封裝了Mybatis-Plus,所以我采用了Mybatis-Plus的分頁(yè)插件
一、問(wèn)題說(shuō)明
場(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è)問(wèn)題:
1、數(shù)據(jù)總條數(shù)以及頁(yè)數(shù)不對(duì)
2、數(shù)據(jù)分頁(yè)數(shù)量不對(duì)
3、數(shù)據(jù)混亂
已下是我有問(wèn)題的代碼:
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)超過(guò)最大頁(yè)數(shù)時(shí)不會(huì)報(bào)錯(cuò) pii.setOverflow(true); return pii; } }
3、創(chuàng)建mapper層
創(chuàng)建了一個(gè)返回實(shí)體類(lèi)
TeacherVO
,包括老師信息以及學(xué)生信息,以及一個(gè)傳入的參數(shù)類(lèi)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類(lèi) * @param teacherRequestVo 傳入的參數(shù) * @return */ Page<TeacherVO> getAll(Page<TeacherVO> page, TeacherRequestVo teacherRequestVo); }
4、編寫(xiě)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é)生或者超過(guò)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ǔ)句有問(wèn)題
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è)問(wèn)題
1、數(shù)據(jù)不對(duì)
2、條數(shù)和頁(yè)數(shù)不對(duì)
1、沒(méi)條件查詢只分頁(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èn)題都可以解決,無(wú)論是用去重,還是GROUP BY
都可以實(shí)現(xiàn),我下面采用GROUP BY
5、最終方案
加上
GROUP BY
進(jìn)行去重,其他地方都沒(méi)改動(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é)果了,沒(méi)必要了,大家可自行測(cè)試
到這里問(wèn)題完美解決
三、結(jié)束語(yǔ)
本人寫(xiě)過(guò)的所有解決什么問(wèn)題都是項(xiàng)目中花了超過(guò)1個(gè)多小時(shí)才解決的問(wèn)題,希望這篇文章對(duì)同學(xué)們有所幫助,不喜勿噴,有任何問(wèn)題都可以評(píng)論,最后送上我的兩句座右銘:
任何人都不會(huì)在意你成功的過(guò)程,只在意你成功的結(jié)果,在你沒(méi)有成功之前,切勿向別人強(qiáng)調(diào)過(guò)程;
請(qǐng)不要假裝努力,結(jié)果不會(huì)陪你演戲;
到此這篇關(guān)于Mybatis-Plus或PageHelper多表分頁(yè)查詢總條數(shù)不對(duì)問(wèn)題的解決方法的文章就介紹到這了,更多相關(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)單不需要寫(xiě)sql的多表查詢
- mybatis-plus多表查詢操作方法
相關(guān)文章
hibernate-validator如何使用校驗(yàn)框架
高效、合理的使用hibernate-validator校驗(yàn)框架可以提高程序的可讀性,以及減少不必要的代碼邏輯,本文主要介紹了hibernate-validator如何使用校驗(yàn)框架,感興趣的可以了解一下2022-04-04java用兩個(gè)例子充分闡述多態(tài)的可拓展性介紹
下面小編就為大家?guī)?lái)一篇java用兩個(gè)例子充分闡述多態(tài)的可拓展性介紹。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06JavaSE系列基礎(chǔ)包裝類(lèi)及日歷類(lèi)詳解
這篇文章主要介紹的是JavaSE中常用的基礎(chǔ)包裝類(lèi)以及日歷類(lèi)的使用詳解,文中的示例代碼簡(jiǎn)潔易懂,對(duì)我們學(xué)習(xí)JavaSE有一定的幫助,感興趣的小伙伴快來(lái)跟隨小編一起學(xué)習(xí)吧2021-12-12IntelliJ IDEA像Eclipse一樣打開(kāi)多個(gè)項(xiàng)目的圖文教程
這篇文章主要介紹了IntelliJ IDEA像Eclipse一樣打開(kāi)多個(gè)項(xiàng)目的方法圖文教程講解,需要的朋友可以參考下2018-03-03java8新特性之stream的collect實(shí)戰(zhàn)教程
這篇文章主要介紹了java8新特性之stream的collect實(shí)戰(zhàn)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08SpringBoot部署到騰訊云的實(shí)現(xiàn)示例
記錄一下自己第一次部署springboot項(xiàng)目,本文主要介紹了SpringBoot部署到騰訊云的實(shí)現(xiàn)示例,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Springboot+Netty+Websocket實(shí)現(xiàn)消息推送實(shí)例
這篇文章主要介紹了Springboot+Netty+Websocket實(shí)現(xiàn)消息推送實(shí)例,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02