暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Mybatis一对多与PageHelper产生的bug

一叶扁舟 2021-05-14
3066

image.png

一、问题记录

在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条

image.png

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

  • 关于total

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

  • 关于返回结果

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

【方法二】

方法二首先执行了如下sql

select id, name from teacher

查询结果2条

image.png

如果使用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>
最后修改时间:2022-04-19 10:29:13
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论