9. MyBatis加载策略
Posted 海洋的渔夫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9. MyBatis加载策略相关的知识,希望对你有一定的参考价值。
9. MyBatis加载策略
前言
在上一篇中我们已经熟悉了 MyBatis 的嵌套查询,而嵌套查询是通过多个单表查询多次执行来实现的。
不过在使用的过程中,有些时候我们希望嵌套查询只执行前面的一些SQL,不那么着急去执行后面所有的SQL,因为有时候不一定需要立即查询所有的结果出来。
那么要实现这个目标,我们就要来认识一下 MyBatis 的 加载策略。
什么是加载策略
-
当多个模型(表)之间存在关联关系时, 加载一个模型(表)的同时, 是否要立即加载其关联的模型, 我们把这种决策称为加载策略
-
如果加载一个模型(表)的时候, 需要立即加载出其关联的所有模型(表), 这种策略称为立即加载
-
如果加载一个模型的时候, 不需要立即加载出其关联的所有模型, 等到真正需要的时候再加载, 这种策略称为延迟加载(懒加载)
Mybatis中的加载策略有两种: 立即加载和延迟加载, 默认是立即加载
“注意:延迟加载是在嵌套查询基础上实现的
”
加载的分类
-
前提: 在嵌套查询基础上才有懒加载
-
懒加载(lazy)需要了才去加载
-
立即加载(eager)不论你是否需要,都是直接加载
“下面我们先来看看该如何配置,最后再写一个案例来熟悉熟悉。
”
配置延迟加载
全局
“官网文档 https://mybatis.org/mybatis-3/
”
在 SqlMapConfig.xml
,设置开启全局延迟加载
<!--全局配置: 写在properties标签之后,typeAliases标签之前 -->
<settings>
<!--开启延迟(懒)加载 true 开始 false(默认值) 关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
局部
mapper映射文件,指定某一个select标签配置
<association></association> 标签
<collection></collection> 标签
fetchType=""属性
eager 立即加载
lazy 延迟加载
“注意:局部优先级高于全局的...
”
触发(立即)加载
有这样一个全局配置lazyLoadTriggerMethods
, 定义的类方法会触发立即加载
也就说当你调用类定义的方法时, 会执行数据加载, 它的默认值是equals,clone,hashCode,toString
,也就是说当调用某个类的方法(例如:user.equals
user.toString
)就会触发数据加载。
<!--全局配置-->
<settings>
<!--开启延迟(懒)加载 true 开始 false(默认值) 关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--触发立即加载的配置
默认值:equals,clone,hashCode,toString
value="" 覆盖了默认值,表示在执行上述四个方法时,不会触发立即加载...
只有在执行orders.get方法获取时,触发数据加载...
-->
<setting name="lazyLoadTriggerMethods" value=""/>
</settings>
应用场景
-
需求: 查询某个订单以及对应的用户 a. 联合查询: 直接查询两张表的结果 (表数据小) b. 嵌套查询: 分别查询订单 和 用户的数据 (表数据大)
-
什么样的场景使用立即加载 查询订单的时候,需要立即知道订单所属的用户
-
什么样的场景使用延迟加载(什么时候用,什么时候查询,提高数据库性能) 查询订单的时候,不许立即知道订单所属的用户
默认加载(立即加载)演示
-
1.回到我们上一篇嵌套查询的 订单 Orders 与 用户 Users 的一对一嵌套查询,测试方法执行如下:
@Test
public void test02(){
SqlSession session = MyBatisUtil.getSqlSession();
OrdersMapper mapper = session.getMapper(OrdersMapper.class);
// 订单编号 = 1, 查询该订单的信息以及对应的用户信息
Orders orders = mapper.findOrderByIdWithUser(1);
MyBatisUtil.commitAndClose(session);
}
从上面的结果来看,我们只需要输出 订单 orders 的信息,但是嵌套查询也把 user 的信息执行查询出来了。
“疑问:那么如果我们只想查询 orders 的信息,并不想立即把 user 的信息进行查询,只有当需要使用 user 信息的时候,才进行查询。该怎么做呢?
”
下面我们来配置一下 全局延迟加载。
全局延迟加载
-
1.在 SqlMapConfig.xml
,设置开启全局延迟加载。
<!--全局配置: 写在properties标签之后,typeAliases标签之前 -->
<settings>
<!--开启延迟(懒)加载 true 开始 false(默认值) 关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
-
2.配置完毕全局延迟加载之后,我们再次执行嵌套查询,看看执行的 SQL 情况:
-
3.打印 orders 信息,执行 orders 属性中的 user.toString() ,触发执行 user 用户信息的 查询
在上面我们可以看到并没有立即触发执行 user 用户信息的查询,那么下面我们来触发一下。如下:
局部立即加载
在上面我们通过打印 user 信息来进行加载,那么我们又回到希望就算不打印 user 信息,却需要立即加载的需求呢?
我们可以配置 局部立即加载,如下:
OrdersMapper.xml
<!--
设置查询结果集 resultMap, 结果映射为 Orders 类
-->
<resultMap id="myorder" type="Orders" autoMapping="true">
<!-- 设置 id 字段映射 Orders 类的属性 id -->
<id property="id" column="id"/>
<!-- 设置普通字段 ordertime 映射 Orders 类的属性 ordertime -->
<result property="ordertime" column="ordertime"/>
<!--
# 嵌套查询重点:
0. 目的
select * from user where id = ?
映射到 orders.user属性中
1. 编写查询user表的语句:
UserMapper.findUserById -> UserMapper.xml
2. 嵌套到这里
association标签的两个属性
a. column : 条件 (执行查询方法的参数)
b. select : 调用第二句sql执行
接口的权限定名.方法名
UserMapper.findUserById(用户id)
-->
<association property="user" javaType="user" autoMapping="true"
fetchType="eager"
column="uid"
select="com.lijw.dao.UserMapper.findUserById">
<id property="id" column="uid"/>
<result property="username" column="username"/>
</association>
</resultMap>
<select id="findOrderByIdWithUser" resultMap="myorder">
select * from orders where id = #{id}
</select>
触发(立即)加载
-
1.在上面我们已经实现了局部立即加载,让我们回退一下。去除一下这个局部立即加载。
-
2.此时如果要加载查询 user 信息,只要打印 orders 信息,从而触发 orders 的属性 user.toString()
的方法
可以看到此时已经触发了 user 的查询加载了。
那么为什么会触发呢?这是因为立即加载的方法默认值是equals,clone,hashCode,toString
,下面我们来修改一下这些方法,让其不立即加载来试试。
-
3.修改立即加载的 类方法:修改默认方法,去除 toString()
方法
sqlMapConfig.xml
<!--全局配置: 写在properties标签之后,typeAliases标签之前 -->
<settings>
<!--开启延迟(懒)加载 true 开始 false(默认值) 关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--触发立即加载的配置
默认值:equals,clone,hashCode,toString
value="" 覆盖了默认值,表示在执行上述四个方法时,不会触发立即加载...
只有在执行orders.get方法获取时,触发数据加载...
-->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode"/>
</settings>
-
4.使用 order.getUser()
方法触发 user 数据加载
以上是关于9. MyBatis加载策略的主要内容,如果未能解决你的问题,请参考以下文章