Mybatis中PageHelper一对多查询分页问题

请注意,本文编写于  1,009  天前,最后编辑于  1,009  天前,内容可能已经不具有时效性,请谨慎参考。

PageHelper一对多查询分页问题

在一个项目中,用到了PageHelper作为分页工具,正常使用没有问题,但是当碰到一对多联合查询分页的时候,查询语句用到了join,PageHelper就出现了问题,导致分页不准确,在网上查阅资料后,发现利用Mybatis中的嵌套子查询可以解决这个问题

一、实体类

需要用到一对多查询的实体

Task.java

/**
 * @Auther: kiritoghy
 * @Date: 19-7-26 上午9:17
 */
public class Task {
    private Long taskId;
    private String taskName;
    private String taskDesc;
    private int imageNumber;
    private int taskType;
    private List<Long> userIds;
    private List<Long> reviewerIds;
    private List<Long> labelIds;
    private List<UserInfo> users;
    private List<String> reviewers;
    private int finish;
}

其中userIds,reviewerIds,labelIds等List需要用到一对多查询

二、Mapper

1. 建立resultMap

<resultMap id="BaseResultMap" type="com.uestc.labelproject.entity.Task">
    <id column="task_id" jdbcType="BIGINT" property="taskId" />
    <result column="task_name" jdbcType="VARCHAR" property="taskName" />
    <result column="task_desc" jdbcType="VARCHAR" property="taskDesc" />
    <result column="image_number" jdbcType="INTEGER" property="imageNumber"/>
    <result column="task_type" jdbcType="INTEGER" property="taskType"/>
    <result column="finish" jdbcType="INTEGER" property="finish"/>
    <collection property="userIds" ofType="Long" select="selectUserId" column="task_id">
        <result column="user_id" jdbcType="BIGINT"/>
    </collection>
    <collection property="labelIds" ofType="Long" select="selectLabelId" column="task_id">
        <result column="label_id" jdbcType="BIGINT"/>
    </collection>
    <collection property="reviewerIds" ofType="Long" select="selectReviewerId" column="task_id">
        <result column="reviewer_id" jdbcType="BIGINT"/>
    </collection>
</resultMap>

基本的resultMap格式都不变,一对多的查询就是加入collection,有点区别的就是其中的参数加入了select="",这个便是子查询

2. 主查询

<select id="getTaskList" resultMap="BaseResultMap">
  select t.task_id,
          t.task_name,
          t.image_number,
          t.task_type,
          (select count(*) from image i where i.task_id = t.task_id and i.user_confirm_id is not null) finish,
          t.task_desc
  from task t where t.is_created = 1
</select>

3. 子查询

<select id="selectUserId" parameterType="Long" resultType="Long">
    select user_id from taskuserinfo where task_id = #{task_id}
</select>
<select id="selectLabelId" parameterType="Long" resultType="Long">
    select label_id from tasklabelinfo where task_id = #{task_id}
</select>
<select id="selectReviewerId" parameterType="Long" resultType="Long">
    select reviewer_id from taskreviewerinfo where task_id = #{task_id}
</select>

三、Controller

现在就可以直接使用PageHelper来进行分页
就是最基本的用法

PageHelper.startPage(page,limit);
List<Task> tasks = adminTaskService.getTaskList();

这样就可以成功分页

四、其他一些问题

这样带来的问题就是1+N的问题,即
例如1次select查询到N个Task后,对于查询到的每个Task,又会进行一次select子查询,因此一共是1+N次,造成性能消耗极大,因此可以在项目配置中对Mybatis使用懒加载

lazyLoadingEnabled=true

这样当在需要用到该子查询的数据时,才会进行子查询,在一定程度上缓解1+N带来的性能问题

当然也还有其他解决办法,例如使用Spring Data Jpa,但是当时项目已经开发到后期,再换持久层的框架成本较大,再者此项目的数据量并不大,只有少量一对多的查询需要分页,然后用到子查询,其余一对多的查询可以直接使用join,因此还是继续使用Mybatis