mybatis之一对多分页处理

1.表结构

文章表,实体类和结构一样

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="BArticle对象", description="")
public class BArticle implements Serializable {
    private static final long serialVersionUID=1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
    * 文章标题
    */
    @ApiModelProperty(value = "文章标题")
    private String title;

    /**
    * 用户ID,对应user表id
    */
    @ApiModelProperty(value = "用户ID,对应user表id")
    private Long userId;

    /**
    * 文章封面图片
    */
    @ApiModelProperty(value = "文章封面图片")
    private String coverImage;

    /**
    * 文章专属二维码地址
    */
    @ApiModelProperty(value = "文章专属二维码地址")
    private String qrcodePath;

    /**
    * 编辑器类型,0 markdown,1 html
    */
    @ApiModelProperty(value = "编辑器类型,0 markdown,1 html")
    private Integer editorType;
}

用户表

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="OUser对象", description="")
public class OUser implements Serializable {

    private static final long serialVersionUID=1L;

    /**
    * 用户ID
    */
    @ApiModelProperty(value = "用户ID")
    @TableId(value = "user_id", type = IdType.AUTO)
    private Long userId;

    /**
    * 用户名
    */
    @ApiModelProperty(value = "用户名")
    private String username;

    /**
    * 邮箱
    */
    @ApiModelProperty(value = "邮箱")
    private String email;

    /**
    * 联系电话
    */
    @ApiModelProperty(value = "联系电话")
    private String mobile;

    /**
    * 状态 0锁定 1有效
    */
    @ApiModelProperty(value = "状态 0锁定 1有效")
    private Integer status;

    /**
    * 创建时间
    */
    @ApiModelProperty(value = "创建时间")
    private LocalDateTime createTime;

    /**
    * 修改时间
    */
    @ApiModelProperty(value = "修改时间")
    private LocalDateTime updateTime;

    /**
    * 最近访问时间
    */
    @ApiModelProperty(value = "最近访问时间")
    private LocalDateTime lastLoginTime;

    /**
    * 性别 0男 1女
    */
    @ApiModelProperty(value = "性别 0男 1女")
    private Integer sex;

    /**
    * 主题
    */
    @ApiModelProperty(value = "主题")
    private String theme;

    /**
    * 头像
    */
    @ApiModelProperty(value = "头像")
    private String headImg;

    /**
    * 描述
    */
    @ApiModelProperty(value = "描述")
    private String description;


}

一对多

一个作者拥有多篇文章
这里选择新建实体类接收

@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Accessors(chain = true)
@ApiModel(value="UserArticleDto对象", description="")
public class UserArticleDto extends OUser {

    private List<BArticle> articleList;
}

查询方法一、

	@ResultMap("selectUserArticle")
    @Select("select a.user_id,a.username,a.email,a.mobile,a.sex,a.theme,a.head_img,
    b.* from o_user a left join b_article b on a.user_id=b.user_id")
    List<UserArticleDto> selectUserArticle();

映射xml

	
	<resultMap id="selectUserArticle" type="com.git.model.dto.UserArticleDto" extends="BaseResultMap">
        <collection property="articleList" ofType="com.git.model.entity.BArticle" autoMapping="true">collection>
    resultMap>

先上sql日志

2019-09-21 16:53:23.518 DEBUG 17156 --- [           main] c.g.m.OUserMapper.selectUserArticle      : ==>  Preparing: select a.user_id,a.username,a.email,a.mobile,a.sex,a.theme,a.head_img,b.* from o_user a left join b_article b on a.user_id=b.user_id 
2019-09-21 16:53:23.541 DEBUG 17156 --- [           main] c.g.m.OUserMapper.selectUserArticle      : ==> Parameters: 
2019-09-21 16:53:23.581 DEBUG 17156 --- [           main] c.g.m.OUserMapper.selectUserArticle      : <==      Total: 22

结果mybatis之一对多分页处理_第1张图片
其实最终结果是以用户表为主体,得到10条数据

查询方法二、

List<UserArticleDto> selectUserArticle2();

映射xml

    <resultMap id="selectUserArticle2" type="com.git.model.dto.UserArticleDto" extends="BaseResultMap">
        <collection property="articleList" ofType="com.git.model.entity.BArticle" select="selectArticle111" column="user_id" autoMapping="true">collection>
    resultMap>


    <select id="selectUserArticle2" resultMap="selectUserArticle2">
select user_id,username,email,mobile,sex,theme,head_img from o_user
    select>

    <select id="selectArticle111" resultType="com.git.model.entity.BArticle">
        select * from b_article where user_id=#{user_id}
    select>

这里面映射里面使用了第二次查询,结果和第一种方法一样的,
但是却执行的多条sql,这就是所谓的n+1问题,

现在进行分页,先说第二种分页处理,这种简单的处理方式直接用mybatisPlus的分页

 	@Test
    public void testOneToMany2(){
        Page<UserArticleDto> page = new Page<>();
        page.setSize(5);
        page.setCurrent(2);
        page = oUserService.selectUserArticle2(page);
        System.out.println(page);
    }

	@Override
    public Page<UserArticleDto> selectUserArticle2(Page<UserArticleDto> page) {
        return page.setRecords(oUserMapper.selectUserArticle2(page));
    }
List<UserArticleDto> selectUserArticle(Page<UserArticleDto> page);

这种分页,sql不用改变
最后结果
mybatis之一对多分页处理_第2张图片
打印的sql
mybatis之一对多分页处理_第3张图片
可以看到这种情况虽然可以分页但是执行了很多的sql,在不追求性能的情况下简单处理也未尝不可。

现在想使用第一种方式进行分页
主表为用户表,现在先查询主表的条数作为总记录数,这里手工分页。直接在里面用limit

改进如下

@Test
    public void testOneToMany(){
        Page<UserArticleDto> page = new Page<>();
        page.setSize(5);
        page.setCurrent(1);
        page = oUserService.selectUserArticle(page);
        System.out.println(page);
    }

service里面手工分页

 @Override
    public Page selectUserArticle(Page page) {
        //先查询一次总数
        page.setTotal(oUserMapper.selectTotal());//总数
        Long current = page.getCurrent();//当前页
        Long size = page.getSize();//每页大小
        Long index = (current-1)*size;//数据库分布下标
        return page.setRecords(oUserMapper.selectUserArticle(index,size));
    }

sql

    @ResultMap("selectUserArticle")
    @Select("select * from\n" +
            "(select user_id,username,email,mobile,sex,theme,head_img from o_user ORDER BY create_time desc LIMIT #{index},#{size}) a\n" +
            "left join b_article b on a.user_id=b.user_id")
    List<UserArticleDto> selectUserArticle(@Param("index") Long index, @Param("size") Long size);

随后结果和上面的一样,唯一不同的就是执行了两次sql,一次查询总记录数,一次查询数据,并且返回的记录数不等于分页条数
mybatis之一对多分页处理_第4张图片

打印的sql

2019-09-21 17:10:16.074 DEBUG 5228 --- [           main] com.git.mapper.OUserMapper.selectTotal   : ==>  Preparing: select count(1) from o_user 
2019-09-21 17:10:16.099 DEBUG 5228 --- [           main] com.git.mapper.OUserMapper.selectTotal   : ==> Parameters: 
2019-09-21 17:10:16.121 DEBUG 5228 --- [           main] com.git.mapper.OUserMapper.selectTotal   : <==      Total: 1
2019-09-21 17:10:16.124 DEBUG 5228 --- [           main] c.g.m.OUserMapper.selectUserArticle      : ==>  Preparing: select * from (select user_id,username,email,mobile,sex,theme,head_img from o_user ORDER BY create_time desc LIMIT ?,?) a left join b_article b on a.user_id=b.user_id 
2019-09-21 17:10:16.125 DEBUG 5228 --- [           main] c.g.m.OUserMapper.selectUserArticle      : ==> Parameters: 0(Long), 5(Long)
2019-09-21 17:10:16.146 DEBUG 5228 --- [           main] c.g.m.OUserMapper.selectUserArticle      : <==      Total: 17

结束

上面处理方式最简单的结果就是采用分布查询,虽然执行的sql多了但是清晰明了,
另外一种其实就是子查询,先查询总记录数,在子查询里面分页。

本文为作者原创,转载请申请。

你可能感兴趣的:(mybatis,一对多分页,mybatisPlus)