浅析Mybatis一对多与PageHelper产生的问题

一、问题记录

  在 mybatis 中使用 collection 映射一对多关系的结果集时,会存在2个问题:

1、问题一:total总数与实际返回数量不一致

2、问题二:实际返回数据有问题

二、Mybatis一对多的两种mapper写法

  Mybatis提供了两种一对多的解决方案:一种是嵌套结果,一种是嵌套查询

1、嵌套结果查询:

  多表关联查询出一对一的关系,再封装成Teacher对象

<select id="getTeacher" resultMap="TeacherMap">
    select t.id id, t.name tname, s.id sid, s.name sname, s.tid tid
    from teacher t
    left join student s
    on t.id = s.tid
</select>

<resultMap type="Teacher" id="TeacherMap">
    <result property="id" column="id"/>
    <result property="name" column="tname"/>
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

2、嵌套查询

  先查出Teacher对象,再遍历匹配出相应的Student对象集合

<select id="xxx" resultMap="TeacherMap">
    select id, name from teacher
</select>

<select id="selectStudents" resultType="Student">
    select id, tid, name from student
</select>

<resultMap type="Teacher" id="TeacherMap">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="students" ofType="Student" select="selectStudents"column="id" javaType="java.util.List">
        <result property="id" column="id"/>
        <result property="tid" column="tid"/>
        <result property="name" column="name"/>
    </collection>
</resultMap>

三、问题剖析

1、方法一采用关联查询的方式查询数据。

select t.id id, t.name tname, s.id sid, s.name sname, s.tid tid
from teacher t
left join student s
on t.id = s.tid

  查询结果如下4条

image.png

  如果使用PageHelper,会在以上sql种拼接limit,这样产生的影响是:

(1)对 total 的影响

  因为老师只有2个,我们需要的返回total是2,但是由于多表关联查出来的是以上结果,那么total就会返回4,导致total错误,进而导致页面分页也有问题

(2)对返回结果的影响

  • 如果pagesize >= 4,那所有结果均返回,并且会生成Teacher对象,返回两条结果。没问题
  • 如果pagesize < 4, 比如是2,那李老师就被limit掉了,返回结果只有张老师一个人。有问题

  问题原因:因为 teacher 和 student 表是一对多的关系,所以在关联查询时,虽然是查出来了 4 条记录,但是这 4 条记录中,teacher 有重复的(因为一个 teacher 有多个学生)。而这些记录在封装成 Student 对象返回前端时,会按 Student 进行逐个封装,这样就会出现数量减少的情况。

2、方法二首先执行了如下sql

select id, name from teacher

  查询结果2条

image.png

  如果使用PageHelper,会在以上sql种拼接limit

(1)关于 total

  由于pageHelper只会对紧接着的第一个sql起作用,因此total返回2,没问题

(2)关于返回结果

  PageHelper不会影响后面的sql,因此,不影响结果。没问题

  所以在使用 pageHelper 加一对多的映射时,尽量选用“嵌套查询”的方式。

原文地址:https://www.cnblogs.com/goloving/p/14882543.html