mybatis 的延迟加载
mybatis 的延迟加载
(1)什么是延迟加载?
延迟加载,也称为懒加载(LazyLoding)。
当代码中执行到查询语句时,并不是直接到DB中执行select语句进行查询,而是根据设置好的延迟策略,将查询向后推迟。这就称为延迟加载。
使用延迟加载可以减轻DB服务器的压力。
resultMap中的association和collection标签具有延迟加载的功能。
(2)Mybatis的延迟加载功能
MyBatis的延迟加载
1)只能对关联对象进行查询时,使用延迟加载策略。对于主加载对象,均采用直接加载。
2)要应用延迟加载查询,只能使用多表单独查询,而不能使用多表连接查询。因为多表连接查询的本质是查询一张表,将多张表首先连接为了一张表后,再进行的查询。 查询一个信息,就会将所有信息全部查询到。
(3) 基本概念
1)主加载对象
如: country (国家) 一方 根据国家的id 去查询部长
2)关联对象
如:minister(部长)多方 根据国家的id
去查询部长
3)主表
如:country 表
4)关联表,也称为从表
如:minister 表
(4) Mybatis延迟加载策略-三种
延迟加载策略是指到DB中真正执行select语句进行查询的时机设置。
MyBatis中的延迟加载策略共分三种:
1)直接加载:代码中执行到查询语句,马上就到DB中执行select查询。
2)侵入式延迟加载(lazyLoadingEnabled
= true ,aggressiveLazyLoading = true [ə'gresɪv]):将关联对象的详情侵入到了主加载对象详情之中,作为主加载对象的详情的一部分出现。当要访问主加载对象的详情时,需要将主加载对象所有详情进行查询,但由于关联对象详情作为主加载对象详情的一部分出现了,所以,这个查询不仅会查询主表,还会查询关联表。(对象详情既就是对象的数据)
3)深度延迟加载(lazyLoadingEnabled
= true, aggressiveLazyLoading = false):当需要访问主加载对象详情时,只会查询主表,而不会查询关联表。只有当真正访问关联对象详情时,才会查询关联表。
(5)Mybatis 延迟加载的开启方式
Mybatis在核心配置文件(mybtais.xml)提供了一个 settings 标签,用于设置Mybtais的属性,改变Mybatis的状态。其中有两个属性字段是用于延迟加载的,分别是 lazyLodingEnabled和aggressiveLazyLoding。
图1mybatis 中文官方文档settings标签中的延迟加载
详解:
LazyLodingEnabled 延迟加载的总开关,aggressiveLazyLoading 侵入式延迟加载的开关
侵入式延迟加载不开启既aggressiveLazyLoading = false,就是自动开启了深度加载。
注意:
在mybatis 版本4.1.3 版本以下,aggressiveLazyLoading 的默认值为true,既默认开启了侵入式延迟加载。
在mybatis 版本4.1.3 版本以上,aggressiveLazyLoading 的默认值为false,既默认不开启侵入式延迟加载。
(5.1)Mybatis 延迟加载在项目的设置
1)在mybatis.xml 中开启全局的延迟加载和侵入式的延迟加载
注意:settings 配置的位置需要在别名(typeAliases)配置之前
<settings>
<!-- 延迟加载的总开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延迟加载开关:延迟加载总开关在开启状态下,本开关才起作用 -->
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
图2settings配置的位置
2)测试关联对象的侵入式延迟加载
条件:开启延迟加载总开关(lazyLoadingEnabled = true)
开启侵入式延迟加载(aggressiveLazyLoading
= true)
测试:mapper.xml(对于关联对象,必须使用多表单独查询)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.abc.dao.ICountryDao">
<!-- 多表单独查询 -->
<select id="selectMinisterByCountry" resultType="Minister">
select mid,mname from minister where countryId=#{ooo}
</select>
<!-- 定义结果映射关系 -->
<resultMap type="Country" id="countryMap">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
<!-- ofType解释为element of type ,元素类型 -->
<collection property="ministers"
ofType="Minister"
select="selectMinisterByCountry"
column="cid"/>
</resultMap>
<select id="selectCountryById" resultMap="countryMap">
select cid,cname from country where cid=#{xxx}
</select>
</mapper>
测试代码:
图3侵入式延迟加载测试代码
在debug 模式下,当执行完syso(country.getCname()) 的时候,第二条查询语句就已经执行了。注意,这里是执行完这一句代码之后,mybatis才对关联对象进行查询。
这也就是侵入式延迟加载,把我们的关联对象的详情侵入到了主加载对象中了,导致我们查询主加载对象的详情的时候关联对象的信息也被加载了。
结果:
图4侵入式延迟加载测试结果
3)测试关联对象的深度延迟加载
条件:开启延迟加载的总开关(lazyLoadingEnabled = true)
关闭侵入式延迟加载的开关(aggressiveLazyLoading
= false)
测试:mybatis.xml配置文件
<settings>
<!-- 延迟加载的总开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 侵入式延迟加载开关:延迟加载总开关在开启状态下,本开关才起作用 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
执行
图5深度延迟加载测试
当需要访问主加载对象详情时,只会查询主表,而不会查询关联表。只有当真正访问关联对象详情时,才会查询关联表。