Mybatis学习--16.Mybatis的高级映射及延迟加载
Mybatis的高级映射及延迟加载
高级映射
之前我们使用mybatis时,都是单表映射——一张数据库表对应一个java类。但在实际应用中,往往有多张表,且这些表之间是存在某种关系的比如:一对一、一对多、多对一等,针对以上情况,mybatis中提供了高级映射机制,来解决数据库表与java对象之间的映射关系。
以下以班级表和学生表为例
有两种解决方案:
将表的关系看作是多对一,即多个学生对应一个班级。以多的一方(Student)作为主表,Student对象作为主对象,Clazz对象作为副对象。通过Student对象可以找到对应的Clazz对象,因此在Student中添加一个Clazz属性。
mybatis中实现多对一映射的方法
一条sql语句,级联属性的方法
<resultMap id="studentResultMap" type="student"> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="clazz.cid" column="cid"></result> <result property="clazz.cname" column="cname"></result> </resultMap> <select id="selectById" resultMap="studentResultMap"> select s.id,s.name,c.cid,c.cname from t_stud s left join t_clazz c on s.cid = c.cid where s.id = #{id} </select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2. 一条sql语句,采用association标签进行表的关联。
* ```xml
<resultMap id="studentResultMap2" type="student">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<!-- property: 需要关联的pojo类的属性,在本例中就是Student类的clazz属性-->
<!-- javaType:需要关联的Java类,在本例中就是Clazz类,这里使用了别名-->
<association property="clazz" javaType="Clazz">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
</association>
</resultMap>
<select id="selectById2" resultMap="studentResultMap2">
select
s.id,s.name,c.cid,c.cname
from
t_stud s left join t_clazz c on s.cid = c.cid
where s.id = #{id}
</select>
前两种方法都是通过一条sql语句进行多表查询的方式,接下来这种方法是通过两条sql语句进行分步查询。即先根据id获取student,再通过student获得clazz对象。
<!--StudentMapper.xml--> <resultMap id="StudentResultMapStep" type="student"> <id property="id" column="id"></id> <result property="name" column="name"></result> <association property="clazz" select="com.deng.mybatis.mapper.ClazzMapper.selectByCidStep2" column="cid"></association> </resultMap> <select id="selectByIdStep1" resultMap="StudentResultMapStep"> select id,name,cid from t_stud where id = #{id} </select>
1
2
3
4
5
6
* ```xml
<!--ClazzMapper.xml-->
<select id="selectByCidStep2" resultType="clazz">
select cid,cname from t_clazz where cid = #{cid}
</select>这种做法的好处在于,代码可复用以及支持延迟加载(懒加载)
因为拆解成了两步,每一步都可以被复用
支持延迟加载:在使用的时候执行查询语句,不使用的时候不执行查询语句。可以提高性能。
比如:如果我只需要查询student的name,通过前两种方式会将两个表进行匹配,查询时间是n*m的。而如果使用第三种方式并且开启延迟加载,那么就只会执行一条sql语句,查询时间为n。
Preparing: select id,name,cid from t_stud where id = ?
1
2
3
4
5
* 可以在mybatis核心配置文件中的settings标签添加以下代码,开启全局延迟加载,使用后只要是分步查询都会开启延迟加载功能
* ```xml
<setting name="lazyLoadingEnabled" value="true"></setting>可以在association标签中通过设置fetchType = eager来局部关闭延迟加载
就是将表之间的关系看成是一对多,在本例中就是指一个班级对应多个学生。在这种关系下,我们需要将班级表作为主表,班级对象作为主对象。实现的原理就是,先查询某个班级,再通过该班级查询学生。因此需要在Clazz类中添加一个Student集合属性,用来存放查询到的学生。
mybatis中实现一对多关系间的映射的方法
collection标签(类似一对多中的association标签),一条sql语句。通过多表连接查询
<resultMap id="selectByCollectionMap" type="Clazz"> <id property="cid" column="cid"></id> <result property="cname" column="cname"></result> <!-- property: 需要关联的pojo类的属性,在本例中就是Clazz类的studs属性--> <!-- ofType:需要关联的Java类,在本例中就是Student类,这里使用了别名--> <collection property="studs" ofType="student"> <id property="id" column="id"></id> <result property="name" column="name"></result> </collection> </resultMap> <select id="selectByCollection" resultMap="selectByCollectionMap"> select c.cid,c.cname,s.id,s.name from t_clazz c left join t_stud s on c.cid = s.cid where c.cid = #{cid} </select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
*
2. 分步查询.两条sql语句,先根据cid查询clazz对象,再通过cid查询student对象。有同学可能会问,为啥不直接根据cid查询student,那是因为这样做无法查出班级名称。
* ```xml
<!--ClazzMapper.xml-->
<resultMap id="selectByCidStep1" type="clazz">
<id property="cid" column="cid"></id>
<result property="cname" column="cname"></result>
<collection property="studs"
select="com.deng.mybatis.mapper.StudentMapper.selectByCidStep2"
column="cid"></collection>
</resultMap>
<select id="selectByCidStep1" resultMap="selectByCidStep1">
select cid,cname from t_clazz where cid = #{cid}
</select><!--StudentMapper.xml--> <select id="selectByCidStep2" resultType="student"> select id,name from t_stud where cid = #{cid} </select>