mybatis 级联查询

573 阅读1分钟

前言

有时候我们的POJO对象经常不是一个简单的对象,往往存在着一对一或者一对多的关系。就如一个学生可以有一个班主任,有多门课程一样:

public class StudentCourse {
    private String sId;
    private String sName;
    private String sBirth;
    private String sSex;
    private Teacher teacher;
    private List<Course> courseList;

这种情况就是级联了。

mybatis 中的三种级联

  • association:代表一对一关系。
  • collection:代表一对多关系。
  • discriminator:鉴别器,允许根据特定的条件去关联不同的结果集。

association 一对一级联

假定:学生(Student)和班主任(Teacher)是一对一的关系:

public class Student {
    private String sId;
    private String sName;
    private String sBirth;
    private String sSex;
    private Teacher teacher;
<!--查询学生的接口-->
<select id="getStudent" resultMap="oneToOneMap">
    select s_id,s_name,s_birth,s_sex from Student
    where s_id in (01)
</select>

<!--查询老师的接口-->
<select id="selectTeacherById" resultType="om.wys.combineduse.pojo.Teacher">
    select t_name,t_id from Teacher
    where t_id = #{tId}
</select>

<resultMap id="oneToOneMap" type="com.wys.combineduse.pojo.Student">
    <id column="s_id" property="sId" />
    <result column="s_name" property="sName" />
    <result column="s_birth" property="sBirth" />
    <result column="s_sex" property="sSex" />
    <!--在resultMap中调用 查询老师的接口 实现级联查询,column 是 查询老师的接口 的入参-->
    <association property="teacher" column="s_id" select="com.wys.combineduse.dao.StudentMapper.selectTeacherById"/>
</resultMap>

执行的过程:先查询出 Student 的信息,然后根据 column="s_id" 作为老师 的 tId 查询出老师的信息。

collection 一对多级联

假定:学生(StudentCourse)和课程(Course)是一对多的关系:

public class StudentCourse {
    private String sId;
    private String sName;
    private String sBirth;
    private String sSex;
    private Teacher teacher;
    private List<Course> courseList;
<!--查询学生接口-->
<select id="getStudentCourse" resultMap="oneToManyMap">
    select s_id,s_name,s_birth,s_sex from Student
    where s_id in (01)
</select>
<!--查询课程接口 返回值为course-->
<select id="getCourseById" resultType="com.wys.combineduse.pojo.Course">
    select c_id,c_name,t_id from Course
    where t_id = #{tId}
</select>

<resultMap id="oneToManyMap" type="com.wys.combineduse.pojo.StudentCourse">
    <id column="s_id" property="sId" />
    <result column="s_name" property="sName" />
    <result column="s_birth" property="sBirth" />
    <result column="s_sex" property="sSex" />
    <!--一对一的级联查询-->
    <association property="teacher" column="s_id" select="com.wys.combineduse.dao.StudentMapper.selectTeacherById"/>
    <!--一对多的级联查询,自动把Course对象装配进courseList中-->
    <collection property="courseList" column="s_id" select="com.wys.combineduse.dao.StudentMapper.getCourseById"/>
</resultMap>

N+1问题:多一个关联,SQL就要多执行一次。每次取一个Student对象,那么它所有关联的信息都会被取出来。这样会造成SQL执行过多导致性能下降。

另一种级联

上面的级联会有N+1的问题,下面这种方式更加的简单和直接:

<!--   主推这种查询,没有n+1问题!-->
<select id="getStudentCourseByOther" resultMap="oneToManyOtherMap">
    select s.s_id,s.s_name,s.s_birth,s.s_sex,t.t_name,t.t_id,c.c_id,c.c_name,c.t_id from Student s
    left join Teacher t on s.s_id = t.t_id
    left join Course c on t.t_id = c.t_id
    where s_id in (01)
</select>

<resultMap id="oneToManyOtherMap" type="com.wys.combineduse.pojo.StudentCourse">
    <id column="s_id" property="sId" />
    <result column="s_name" property="sName" />
    <result column="s_birth" property="sBirth" />
    <result column="s_sex" property="sSex" />
    <association property="teacher" column="s_id" javaType="com.wys.combineduse.pojo.Teacher">
        <id column="t_id" property="tId" />
        <result column="t_name" property="name" />
    </association>
    <!--ofType属性定义的是collection里面的泛型是上面Java类型,MyBatis会拿定义的Java类和结果集做映射-->
    <collection property="courseList" column="s_id" ofType="com.wys.combineduse.pojo.Course" >
        <id column="c_id" property="cId" />
        <result column="c_name" property="cName" />
        <result column="t_id" property="tId" />
    </collection>
</resultMap>

discriminator 鉴别器