Mybatis的延迟加载

1.什么是延迟加载

当加载用户信息时,不一定就要马上加载他的订单信息或者所有的好友信息,聊天记录等等,这样就需要用到延迟加载。

当我们需要用到数据的时候才进行加载,不用数据的时候就不加载,也可以叫做懒加载。

优点

先从单表查询,需要时再从关联表去关联查询,⼤⼤提⾼数据库性能,因为查询单表要比关联查询多张表速度要快。

缺点

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成⽤户等待时间变长,造成用户体验下降。

在多表中:
        一对多,多对多:通常情况下采用延迟加载
        一对一(多对一):通常情况下采用立即加载

注意:
延迟加载是基于(嵌套查询)来实现的 

2.实现

局部延迟加载

associationcollection标签中都有⼀个fetchType属性,通过修改它的值,可以修改局部的加载策略。 

<?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.lazyload.mapper.IAccountMapper">
 
    <!--将Account的信息和User的信息封装到ResultMap中去-->
    <!--  property表示java实体类中属性的名称,javaType表示属性的类型,ofType表示泛型,column表示应用查询的某列 select表示需要执行的sql语句 fetchType表示是否开启延迟加载eager取消延迟加载,lazy开启延迟加载,默认开启 -->
    <resultMap id="userAccountMap" type="com.lazyload.entites.Account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--一对一的映射关系:配置封装的内容
        select属性指定的内容:查询用户的唯一标识【com.itheima.dao.IAccountMapper+方法名(就是接口中的)】
        column属性指定的内容:根据id查询时,所需要的参数的值(根据id来查询数据库的)
        -->
        <association property="user" column="uid" javaType="com.lazyload.entites.User" select="findAccountByUid" feetchType="lazy"></association>
    </resultMap>
 
    <!--封装的查询所有-->
    <select id="findAllAccount" resultMap="userAccountMap">
        select * from account
    </select>
 
    <!--根据用户id查询账户列表-->
    <select id="findAccountByUid" parameterType="integer" resultType="com.lazyload.entites.Account">
        select * from account where uid=#{uid}
    </select>
 
</mapper>
<?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.lazyload.mapper.IUserMapper">
 
    <!--写入user的resultMap:将user和数据库对应
    作用:建立SQL查询结果字段与实体属性的映射关系
    -->
    <resultMap id="userAccountMap" type="com.lazyload.entites.User">
        <!--主键字段-->
        <!--column所表示的是数据库中的字段名称-->
        <id property="id" column="id"></id>
        <!--非主键字段-->
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <!--Userx下对应的对应Account账户的信息:配置user对象下account的映射-->
        <collection property="accounts"  select="findUserById" column="id"></collection>
    </resultMap>
    <!--查询所有-->
    <select id="findAll" resultMap="userAccountMap">
        select * from user
    </select>
 
    <!--查询一个通过id-->
    <select id="findUserById" parameterType="int" resultType="com.lazyload.entites.User">
        select * from user where id=#{id}
    </select>
</mapper>

参考链接:https://blog.csdn.net/friggly/article/details/124686876?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-0-124686876-blog-108432460.235^v38^pc_relevant_default_base&spm=1001.2101.3001.4242.1&utm_relevant_index=3

当查询用户基本信息时,只返回用户基本信息,而不进行其余账号信息的查询,当触发关键方法的时候才进行查询,具体的进入参考链接学习讲的非常好,到位学习链接。 

全局延迟加载

#全局启用延迟加载
mybatis.configuration.lazy-loading-enable=true

#为false时,所有关联对象都会按需求加载
mybatis.configuration.aggressive-lazy-loading=false

#设置方法触发加载,不设置时默认为下面这几个方法触发
mybatis.configuration.lazy-load-trigger-methods=equals,clone,hashCode

局部加载策略优先级高于全局加载策略,同时在xml映射文件里修改feetchType属性为eager来取消延迟加载。

3、延迟加载原理实现


        它的原理是,使用 CGLIB 或 Javassist( 默认 ) 创建目标对象的代理对象。当调用代理对象的延迟加载属性的 getting 方法时,进入拦截器方法。比如调⽤ a.getB().getName() 方法,进入拦截器的invoke(...) 方法,发现 a.getB() 需要延迟加载时,那么就会单独发送事先保存好的查询关联 B对象的 SQL ,把 B 查询上来,然后调用a.setB(b) 方法,于是 a 对象 b 属性就有值了,接着完成a.getB().getName() 方法的调用。这就是延迟加载的基本原理。

总结:延迟加载主要是通过动态代理的形式实现,通过代理拦截到指定方法,执行数据加载。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值