原文:Mybatis一对多查询,分页显示问题解决方案_mybatis一对多分页问题-CSDN博客
在我们的开发中也许是遇到最多的功能,一张表的分页,多张表一对一功能的分页相信大家写来都是得心应手,但是在一对多分页查询的时候大家写法不对的时候,可能会遇到查询的总条数和实际总条数对不上的问题。不多说下面请看演示。
1:先提供2张表的建表SQL如下【使用的是Mysql】:
CREATE TABLE `School`(
`id` INT(10) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) COMMENT '学校名称',
`create_date` DATE,
`create_by` VARCHAR(20),
PRIMARY KEY (`id`)
);
CREATE TABLE `class`(
`id` INT NOT NULL AUTO_INCREMENT,
`school_id` INT COMMENT 'school表的主键,进行逻辑关联',
`class_name` VARCHAR(20) COMMENT '班级名称。。',
`create_date` DATE,
`create_by` VARCHAR(20),
PRIMARY KEY (`id`)
);
2:初始化的语句。
INSERT INTO School (NAME,create_date,create_by) VALUES('上海交通大学',NOW(),'admin');
INSERT INTO School (NAME,create_date,create_by) VALUES('复旦',NOW(),'admin');
INSERT INTO School (NAME,create_date,create_by) VALUES('同济',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='上海交通大学') a),'计算机一班',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='上海交通大学') a),'计算机二班',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='复旦') a),'通信学院一班',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='复旦') a),'通信学院二班',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='同济') a),'建筑学院一班',NOW(),'admin');
INSERT INTO class (school_id,class_name,create_date,create_by) VALUES((SELECT * FROM (SELECT id FROM school WHERE NAME='同济') a),'建筑学院二班',NOW(),'admin');
然后初始化一个简单的项目,注意还是 Spring boot 加Mybatis-Plus。我的这篇文章介绍的Mybatis-Plus初始化简单项目非常不错,欢迎阅读。
好了我把主要的代码贴出来。
// 首先是最基础的mapper文件,最主要的代码就在这里了,一对多很多人都
// 这样写,但是如果涉及到分页,这样写就不对了,后面会有结果演示。
<resultMap type="io.renren.dto.SchoolDTO" id="schoolMap">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="classDtos" ofType="io.renren.dto.ClassDTO">
<id property="id" column="id"></id>
<result property="schoolId" column="school_id"></result>
<result property="className" column="class_name"></result>
</collection>
</resultMap>
<select id="querySchoolByPage" resultMap="schoolMap">
SELECT a.id,a.name,b.id,b.school_id,b.class_name FROM school a JOIN class b ON a.id=b.school_id
<where>
<if test="query!=null">
<if test="query.name!=null and query.name!=''">
a.name=#{query.name}
</if>
</if>
</where>
</select>
// 2: mapper接口
public interface SchoolDao extends BaseMapper<School> {
// 使用的是Mybatis-Plus的分页插件,按照Mybatis-Plus的规则传参
// 就会自动进行分页拦截
IPage querySchoolByPage(IPage iapge, @Param("query") SchoolQuery query);
}
// 相关的Service和controller
public interface SchoolService extends IService<School> {
IPage<SchoolDTO> querySchoolByPage(IPage<?> page, SchoolQuery query) ;
}
@Service("schoolService")
public class SchoolServiceImpl extends ServiceImpl<SchoolDao, School> implements SchoolService {
@Autowired
private SchoolDao schoolDao ;
@Override
public IPage<SchoolDTO> querySchoolByPage(IPage<?> page, SchoolQuery query) {
return schoolDao.querySchoolByPage(page,query);
}
}
// 里面的Query这个类只要你按照我上面引用的那个文章,下载相关代码
// 就能看到这个类,由于这个类代码太多也不是主要讲的我就不贴出来了。
// 注意Query这个类开发中你也可以自己封装一个更好的类。由于这里不是注意讲
// Mybatis-Plus的我就按照Query这个类给大家展示了。
// 封装起来也很容易按照相应的规则就可以了。
@RestController
@RequestMapping("/school")
public class SchoolController {
@Autowired
private SchoolService schoolService ;
@PostMapping("/query")
// 这里我使用Map接收参数,开发的时候自己要建一个类,不要使用Map
public IPage<SchoolDTO> querySchool(@RequestBody Map<String,Object> params){
return schoolService.querySchoolByPage(new Query<SchoolQuery>().getPage(params),
null); // 为了演示直接传一个null,不需要查询条件,只要分页参数
}
}
好了我们使用PostMan测试一下如下图:
显示的结果如下图:
从上面我们SQL初始化的数据知道School这个表我们就初始化了3条数据,但是给的总的结果是6条,这个是不对的。我们查询的时候每页要查2条数据而显示的结果只要1条数据也不是我们要的结果,所以上面的SQL用来分页查询是不对的,后面就带大家写出正确的SQL。
如下其实就是改一下mapper文件中的sql就行了。其原理就是Mybatis的懒加载,先查询出来School,这个单表查询分页肯定没问题,然后再根据条件查询Class,如下SQL也是比较简单的。
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="io.renren.dto.SchoolDTO" id="schoolMap">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="classDtos" ofType="io.renren.dto.ClassDTO" column="id=id" select="selectClassBySchoolId">
<id property="id" column="id"></id>
<result property="schoolId" column="school_id"></result>
<result property="className" column="class_name"></result>
</collection>
</resultMap>
<select id="querySchoolByPage" resultMap="schoolMap">
SELECT a.id,a.name FROM school a
<where>
<if test="query!=null">
<if test="query.name!=null and query.name!=''">
a.name=#{query.name}
</if>
</if>
</where>
</select>
<select id="selectClassBySchoolId" resultType="io.renren.dto.ClassDTO">
select * from class where school_id=#{id}
</select>
然后使用Postman测试结果如下:
查询第一页,每页显示2条数据,查出来的结果也是完全满足我们的要求,也和我们数据库初始化的总条数一样,一共3条数据【PS上面的Mapper中SQL的写法对ORACLE同样可以使用,因为这次它两个的语法规则是一样的】。
好了读完这篇文章我感觉开发中再遇到一对多的分页查询对你来说很容易了,所以麻烦点点小手关注一下,后面你在开发过程中遇到同样的问题,拿出文章看一下对照着写,很容易就写出来了也不会有问题。也欢迎转发给你感觉可能会使用这个功能的朋友,分享给朋友手留余香【因为赠人玫瑰,手留余香】。