文章目录
-
- 前言
- 一、问题说明
-
- 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 join
加Mybatis
的级联查询,一次性获取所有数据出现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个多小时才解决的问题,希望这篇文章对同学们有所帮助,不喜勿喷
,有任何问题都可以评论,最后送上我的两句座右铭:
任何人都不会在意你成功的过程,只在意你成功的结果,在你没有成功之前,切勿向别人强调过程;
请不要假装努力,结果不会陪你演戏;