
一、问题记录
在mybatis使用collection映射一对多关系的结果集时
- 问题一:total总数与实际返回数量不一致
- 问题二:实际返回数据有问题
二、Mybatis一对多的两种mapper写法
Mybatis提供了两种一对多的解决方案
- 实体类
@Data
public class Teacher {
private int id;
private String name;
// 一个老师对应多个学生
private List<Student> students;
}
@Data
public class Student {
private int id;
private String name;
private String tid;
}
- DAO层
public interface TeacherDAO {
List<Teacher> getTeacher();
}
-
mapper
-
【方法一】:
多表关联查询出一对一的关系,再封装成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>
-
【方法二】:
先查出Teacher对象,再遍历匹配出相应的Student对象集合
<select id="xxx" resultMap="TeacherMap">
select id, name from teacher
</select>
<select id="selectStudents" resultType="Student">
select id, tid, name from student where tid = #{id}
</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>
这种有可能遇到报错:No serializer found for class org.apache.ibatis.executor.loader.javassist.Javassis
需要在主查询的实体类上添加:@JsonIgnoreProperties(value = { “handler” })
三、问题剖析
【方法一】
方法一采用关联查询的方式查询数据。
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
-
关于total
因为老师只有2个,我们需要的返回total是2,但是由于多表关联查出来的是以上结果,那么total就会返回4,导致
total错误,进而导致页面分页也有问题 -
关于返回结果
- 如果pagesize >= 4,那所有结果均返回,并且会生成Teacher对象,返回两条结果。
没问题 - 如果pagesize < 4, 比如是2,那李老师就被limit掉了,返回结果只有张老师一个人。
有问题
- 如果pagesize >= 4,那所有结果均返回,并且会生成Teacher对象,返回两条结果。
【方法二】
方法二首先执行了如下sql
select id, name from teacher
查询结果2条

如果使用PageHelper,会在以上sql种拼接limit
-
关于total
由于pageHelper只会对紧接着的第一个sql起作用,因此total返回2,
没问题 -
关于返回结果
PageHelper不会影响后面的sql,因此,不影响结果。
没问题
【结论】因此,当遇到一对多+PageHelper时使用方法二即可
四、问题补充
4.1、一对多&多参数
-
问题描述
在dao层,传入了两个参数
List<Data> selectDatas(@Param("rid") String rid, @Param("userId") Integer userId);在主查询中,需要使用rid和userId两个参数
<select id="selectDatas" resultMap="DataMap"> select id, name from data where created_by = #{userId} and rid = #{rid} </select>在从查询中,需要使用userId参数和与主查询相关联的dataId
<select id="selectSubDatas" resultType="SubData"> select id, name from sub_data where created_by = #{userId} and id = #{dataId} </select>这个时候该如何处理呢?
-
问题解决
首先,由于userId是传进来的参数,并不属于主表字段,因此需要在主表构建出来这个字段(currentUserId)
<select id="selectDatas" resultMap="DataMap"> select id, name, #{userId} currentUserId from data where created_by = #{userId} and rid = #{rid} </select>从表不变
<select id="selectSubDatas" resultType="SubData"> select id, name from sub_data where created_by = #{userId} and id = #{dataId} </select>ResultMap如下,column=“userId=userId, dataId=id” ,意为从表中用到的userId=主表中的currentUserId,从表用到的dataId=主表的id
<resultMap type="Teacher" id="DataMap"> <result property="id" column="id"/> <result property="name" column="name"/> <collection property="subDatas" ofType="SubData" select="selectSubDatas"column="userId=currentUserId, dataId=id" javaType="java.util.List"> <result property="id" column="id"/> <result property="id" column="id"/> <result property="name" column="name"/> </collection> </resultMap>




