⾼级映射及延迟加载
大约 4 分钟
高级映射解决了多对一、一对多、多对多等关系的映射,是处理复杂sql的必需。
多对一
常⻅的包括三种:
- ⼀条SQL语句,级联属性映射。
- ⼀条SQL语句,使用
<association>标签。 - 两条SQL语句,分步查询。(这种方式常用:优点⼀是可复⽤。优点⼆是⽀持懒加载。)
多对一:在"多"的pojo中添加"一"的一个pojo属性
eg:多个学生对应一个班级,在学生类中,添加一个班级属性的pojo

级联属性映射
<!--配置结果映射,使用 . 指向级联属性,完成级联属性的封装-->
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="clazz.cid" column="cid"/>
<result property="clazz.cname" column="cname"/>
</resultMap>
<!--使用一条sql-->
<select id="selectBySid" resultMap="studentResultMap">
select s.*, c.*
from t_student s
join t_clazz c
on s.cid = c.cid
where sid = #{sid}
</select>定义pojo、使用接口方法:
public class Student {
private Clazz clazz;
...;
}
Student student = mapper.selectBySid(1);使用 <association> 关联级联属性
在结果映射中,配置 <association> 即可:
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<!--关联级联属性,从而对级联属性进行封装-->
<association property="clazz" javaType="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
</association>
</resultMap>- 接口、sql无需更改,仍采用与上相同的sql和接口。
使用 <association> 分步查询
在结果映射中,指定级联属性值来源的sql语句:
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<!--关联级联属性,将执行指定的sql并封装至这个级联属性-->
<association property="clazz"
select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid"
column="cid"/>
<!--select:目标sql的 namespace.id 标识-->
</resultMap>sql不需要一句写完,可用分开写了:
<!--StudentMapper.xml-->
<select id="selectBySid" resultMap="studentResultMap">
select s.* from t_student s where sid = #{sid}
</select>
<!--ClazzMapper.xml-->
<select id="selectByCid" resultType="Clazz">
select * from t_clazz where cid = #{cid}
</select>分步查询的优点:
- 代码复⽤性增强。
- ⽀持延迟加载(懒加载)。
多对⼀延迟加载
延迟加载:级联属性第一次被访问时再进行sql传值、执行、封装结果集,不然就先晾在一旁,防止不必要的资源浪费。
只需要在 <association> 中配置即可(局部方式),必须是分步查询才支持(因为只有这样才有两条sql):
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz"
select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid"
column="cid"
fetchType="lazy"/>
<!--添加 fetchType="lazy" 即启用该级联属性的延迟加载-->
<!--添加 fetchType="eager" 即不启用该级联属性的延迟加载-->
</resultMap>- 只有当第一次访问级联属性时,才会执行sql,不然就不会执行。
全局方式开启延迟加载:
<!--mybatis-config.xml-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>开启全局延迟加载后,不用在
<association>中配置。实际开发中,通常配置全局的延迟加载,在部分不需要延迟加载的
<association>中使用fetchType="eager"来覆盖全局的配置,将该级联属性禁用延迟加载。
一对多
⼀对多时,通常在"⼀"的⼀⽅中有List集合属性。如;
public class Clazz {
private Integer cid;
private String cname;
private List<Student> stus; // 一对多,"多"的集合List
// set get⽅法
// 构造⽅法
// toString⽅法
}
一对多的实现方式:
- 使用
<collection> - 分步查询
使用 <collection> 指定级联属性集
<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--指定级联属性封装的集合以及 *集合中各元素* 的结果映射-->
<collection property="stus" ofType="Student"> <!--指定集合封装至 stus, ofType:集合中元素的类型,允许别名 -->
<!--指定集合中元素的结果映射-->
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
select *
from t_clazz c
join t_student s
on c.cid = s.cid
where c.cid = #{cid}
</select>使用 <collection> 分步查询
同上,将sql拆分,在 <collection> 中进行配置:
<!--ClazzMapper.xml-->
<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--主要看这⾥-->
<collection property="stus"
select="com.powernode.mybatis.mapper.StudentMapper.selectByCid"
column="cid"/>
</resultMap>
<!--sql语句也变化了-->
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
select * from t_clazz c where c.cid = #{cid}
</select>一对多延迟加载
同上述,在 <collection> 中配置 fetchType="lazy|eager" 即可。
支持全局配置。
