使用Mybatis实现延迟加载

本文是上文 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节点下的lazyLoadingEnabledaggressiveLazyLoading两个属性。
  • 无论是一对一还是一对多的关系,都能在映射配置中使用 select和column属性,指定实体类中所引用的对象(或集合)的映射(也就是怎么查询这个引用的对象),而这个查询动作在开启了延迟加载后,只会在需要时被执行。
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis实现延迟加载的原理是通过动态代理技术,当查询到需要延迟加载属性时,不立即去数据库查询,而是返回一个代理对象,等到使用属性时再去查询数据库。 下面是一个简单的示例: 1. 定义User类和Order类,User类中有一个List<Order>属性: public class User { private int id; private String username; private List<Order> orders; // getter和setter } public class Order { private int id; private String orderNo; // getter和setter } 2. 定义UserMapper接口,其中定义一个selectById方法,查询用户信息以及用户的订单信息: public interface UserMapper { User selectById(int id); } 3. 定义UserMapper.xml文件,实现selectById方法: <select id="selectById" resultMap="userResultMap"> select * from user where id = #{id} </select> <resultMap id="userResultMap" type="User"> <id column="id" property="id"/> <result column="username" property="username"/> <collection property="orders" ofType="Order" select="selectOrdersByUserId"/> </resultMap> <select id="selectOrdersByUserId" resultMap="orderResultMap"> select * from order where user_id = #{id} </select> <resultMap id="orderResultMap" type="Order"> <id column="id" property="id"/> <result column="order_no" property="orderNo"/> </resultMap> 4. 在Mybatis配置文件中配置延迟加载: <configuration> <settings> <setting name="lazyLoadingEnabled" value="true"/> </settings> </configuration> 5. 在Java代码中调用selectById方法获取用户信息: User user = userMapper.selectById(1); 此时,只有用户信息被查询出来,用户的订单信息并没有被查询出来,而是返回了一个代理对象。 6. 当使用用户的订单信息时,代理对象会去查询数据库,获取订单信息: List<Order> orders = user.getOrders(); 此时,代理对象会调用selectOrdersByUserId方法查询数据库,获取用户的订单信息。 通过以上过程可以看出,Mybatis实现延迟加载的原理就是通过代理对象实现的。当需要延迟加载属性调用时,代理对象会去查询数据库获取数据,从而实现延迟加载

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值