一、问题记录
在 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条
如果使用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条
如果使用PageHelper,会在以上sql种拼接limit
(1)关于 total
由于pageHelper只会对紧接着的第一个sql起作用,因此total返回2,没问题
(2)关于返回结果
PageHelper不会影响后面的sql,因此,不影响结果。没问题
所以在使用 pageHelper 加一对多的映射时,尽量选用“嵌套查询”的方式。