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

	<!-- 這裏採用一條sql解決,簡單映射,因爲映射結果比較簡單直接自動映射-->
	<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

結果查詢結果
其實最終結果是以用戶表爲主體,得到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不用改變
最後結果
分頁結果
打印的sql
打印的sql
可以看到這種情況雖然可以分頁但是執行了很多的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<UserArticleDto> selectUserArticle(Page<UserArticleDto> 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,一次查詢總記錄數,一次查詢數據,並且返回的記錄數不等於分頁條數
在這裏插入圖片描述

打印的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多了但是清晰明瞭,
另外一種其實就是子查詢,先查詢總記錄數,在子查詢裏面分頁。

本文爲作者原創,轉載請申請。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章