有时候我们的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执行过多导致性能下降。
注意事项:
需要传递多参数时,在column中用需要用"{}"将参数包起来, =左侧的为mapper中定义的param,也就是实体类中映射的字段, =右侧为主查询的数据库的对应表的表字段名 ,
如:
<collection property="highList" column="{id= id,standardId= standard_id}" select="getChildById"/>
单参数传递时不用"{}",如:
<collection property="highRuleList" column="id" select="getHighRuleList"/>
另一种级联
上面的级联会有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>