@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
查询方法二、
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,在不追求性能的情况下简单处理也未尝不可。
现在想使用第一种方式进行分页
主表为用户表,现在先查询主表的条数作为总记录数,这里手工分页。直接在里面用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,一次查询总记录数,一次查询数据,并且返回的记录数不等于分页条数
打印的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多了但是清晰明了,
另外一种其实就是子查询,先查询总记录数,在子查询里面分页。
本文为作者原创,转载请申请。