前言
最近在使用PageHelper时,发现其无法正常对多对多查询出的结果集进行正确分页。原因其实在PageHelper官网写着了:
那么解决该问题便会变得非常棘手,笔者选择的是用MyBatis的方式手动进行分页操作,正好也复习巩固一下SQL语句和多对多映射操作。
一、子查询分页
利用子查询分页可以在SQL层面上解决分页问题,剩下的都交给配置结果集映射(resultMap)来做。
该思路是网上一篇大神的博客提供的:MyBatis一对多或多对多分页查询的结果条数不符合预期的问题解决
使用子查询分页有以下几点需要注意:
SELECT
b.id,b.title,t.id tid,t.name tname
FROM
(SELECT t_blog.`id`,t_blog.title FROM t_blog ORDER BY t_blog.id DESC LIMIT 0,5) b
INNER JOIN
blog_type bt
ON
b.`id`=bt.`bid`
INNER JOIN
t_type t
ON
bt.`tid`=t.`id`
- 这条SQL语句的第四行 :
(SELECT t_blog.`id`,t_blog.title FROM t_blog ORDER BY t_blog.id DESC LIMIT 0,5) b
意思就是将t_blog表的字段先分页查出来,然后将其分页后的结果看作是一个新的表,并将该新表取别名叫b。(order by t_blog.id DESC是按照id降序排列,也是个小细节)
- 既然如此,那剩下的查询语句都以b表为基准,进行内联,多表操作,实现了分页多对多查询
- 查询结果:
这里可以看到,分页的期望是5条数据(LIMIT 0,5),这里却查出来8个数据。但是别忘了,这是多对多查询,还关联了t_type表,最终进行完结果集映射,这8条数据就会变成5条。
二、编写对应的mapper
- 接口
List<BlogQuery> queryAllBlogByLimit(Map<String,Integer> map);
- 实体类:
public class BlogQuery {
private int id;
private String title;
private Date updateTime;
private Boolean recommend;
private Boolean published;
private int typeId;
private List<Type> types;
}
public class Type {
private int id;
private String name;
private List<Blog> blogs; //该Type类型下的所有博客
}
- 对应的mapper
<select id="queryAllBlogByLimit" parameterType="map" resultMap="blogquery">
SELECT
b.id,b.title,b.update_time,b.recommend,b.published,t.id tid,t.name tname
FROM
(SELECT t_blog.`id`,t_blog.title,t_blog.update_time,t_blog.recommend,t_blog.published FROM t_blog ORDER BY t_blog.id DESC LIMIT #{startIndex},#{pageSize}) b
INNER JOIN
blog_type bt
ON
b.`id`=bt.`bid`
INNER JOIN
t_type t
ON
bt.`tid`=t.`id`
</select>
<resultMap id="blogquery" type="com.lubenwei.vo.BlogQuery">
<id property="id" column="id"/>
<result property="title" column="title"/>
<result property="updateTime" column="update_time"/>
<result property="recommend" column="recommend"/>
<result property="published" column="published"/>
<!--如果属性是一个Java类的话,就需要配置association; 如果属性是一个集合, 那就需要配置collection-->
<collection property="types" ofType="Type">
<result property="id" column="tid" />
<result property="name" column="tname" />
</collection>
</resultMap>
到这里MyBatis能做的部分就做完了,前端只需要给我们提供一个Map,里面存放着分页的起始位置(startIndex)和页码容量(pageSize),数据库就会返回想要的分页结果。