本文是上文 Mybatis的多表查询实例的扩展。
------->项目源码
概念
在mybatis的多表操作中,是可以实现查询A时,一并把其关联对象B给查出来的操作。
现在问题来了,若有一对多的关系“用户-钱包”:某用户A名下有1000个钱包,并且有关联查询的需求,那么我们每次查询用户,难道都要把他的1000个钱包全都查询出来吗?当然不是,由于user对象中包含钱包集合的引用,每次查询后,JVM都会在堆中开辟空间来存储这个集合对象,这样会浪费巨大的内存空间,我们不需要钱包信息的时候,当然就不应该去查询它。那么怎么去控制这个查询的时机呢?这就需要Mybatis的延迟加载了。
延迟加载就是在真正使用数据时才发起查询,不用的时候不查询——也叫按需加载(懒加载)。
反之就是立即加载,无论数据是否需要使用,只要调用查询方法,将马上发起查询。
使用association实现延迟加载
多表关系:一对一
使用上文 Mybatis的多表查询实例的一对一的例子——钱包与用户,进行改造。
需求:
查询钱包信息同时查询用户信息。
之前这个例子实现的是 ,查询钱包时,一并把其所属用户查询出来:
目录结构:
先修改映射配置,将sql语句还原为单表查询。
IWalletDAO.xml:
<!-- 查询所有 -->
<select id="findAll" resultMap="walletUserMap">
select * from wallet;
</select>
接着修改xml中的resultMap标签:
<!-- 定义封装wallet和user的resultMap -->
<resultMap id="walletUserMap" type="wallet">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容
select属性指定的内容:查询用户的唯一标识:
column属性指定的内容:用户根据id查询时,所需要的参数的值
-->
<association property="user" column="uid" javaType="user" select="com.zhu.dao.IUserDao.findById"></association>
</resultMap>
select: 填写我们要调用的 select 映射的唯一标识
column : 填写我们要传递给 select 映射的参数
对比图:
这么改了能实现延迟加载么?当然不行,但是这么修改的意义是,原来使用的是一个整体的关联查询(只执行wallet的findAll()就查到了用户信息,因为SQL语句使用了多表查询),现在拆分成了两段,先执行wallet的findAll(),再执行user的findById()。
运行WalletTest.findAll:
从日志可以看出,虽然依然把用户信息查询到了,但是使用的SQL语句是分开执行的。
现在继续配置,在Mybatis官方文档中的XML配置可以看到配置方法:
那么我们在主配置文件中进行添加这部分的设置:
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
将lazyLoadingEnabled置true意味着打开了延迟加载的全局开关,
将aggressiveLazyLoading置false意味着每个延迟加载属性会按需加载(3.4.1 之后版本可不配置因为已默认置false)。
修改测试类,只查钱包信息不查用户信息:
结果:
因为本次只是将 Wallet对象查询出来放入 List 集合中,并没有涉及到 User对象,所以就没有发出 SQL 语句查询钱包所关联的 User 对象的查询。
使用collection实现延迟加载
多表关系:一对多
需求:查询用户信息同时查询钱包信息。
先修改用户的映射配置,SQL语句无需关联查询,collection标签添加select等属性:
select: 填写我们要调用的 select 映射的唯一标识
column : 填写我们要传递给 select 映射的参数
接下来到IWalletDAO接口中定义查询方法:
/**
* 根据用户id查询钱包信息
* @param uid
* @return
*/
List<Wallet> findWalletByUid(Integer uid);
进而到IWalletDAO.xml中配置:
<!-- 根据用户id查询钱包列表 -->
<select id="findWalletByUid" resultType="wallet">
select * from wallet where uid = #{uid}
</select>
测试类UserTest,同样我们只查询用户而暂且不关注它们所关联的钱包:
/**
* 测试查询所有
*/
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
// for(User user : users){
// System.out.println("-----每个用户的信息------");
// System.out.println(user);
// System.out.println(user.getWallets());
// }
}
测试结果:
只查询了用户,而用户对应的钱包并没有查询。
总结
- 使Mybatis支持延迟加载,需要关注主配置中settings节点下的lazyLoadingEnabled与aggressiveLazyLoading两个属性。
- 无论是一对一还是一对多的关系,都能在映射配置中使用 select和column属性,指定实体类中所引用的对象(或集合)的映射(也就是怎么查询这个引用的对象),而这个查询动作在开启了延迟加载后,只会在需要时被执行。