在上一篇中我们已经熟悉了 MyBatis 的嵌套查询,而嵌套查询是通过多个单表查询多次执行来实现的。
不过在使用的过程中,有些时候我们希望嵌套查询只执行前面的一些SQL,不那么着急去执行后面所有的SQL,因为有时候不一定需要立即查询所有的结果出来。
那么要实现这个目标,我们就要来认识一下 MyBatis 的 加载策略。
Mybatis中的加载策略有两种: 立即加载和延迟加载, 默认是立即加载
“注意:延迟加载是在嵌套查询基础上实现的 ”
“下面我们先来看看该如何配置,最后再写一个案例来熟悉熟悉。 ”
“官网文档 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>

@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 信息的时候,才进行查询。该怎么做呢? ”
下面我们来配置一下 全局延迟加载。
SqlMapConfig.xml,设置开启全局延迟加载。
<!--全局配置: 写在properties标签之后,typeAliases标签之前 -->
<settings>
<!--开启延迟(懒)加载 true 开始 false(默认值) 关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>

在上面我们可以看到并没有立即触发执行 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>

user.toString() 的方法
可以看到此时已经触发了 user 的查询加载了。
那么为什么会触发呢?这是因为立即加载的方法默认值是equals,clone,hashCode,toString ,下面我们来修改一下这些方法,让其不立即加载来试试。
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>
order.getUser() 方法触发 user 数据加载