MyBatis(七)延迟加载策略与缓存

一、延迟加载策略

1. 延迟加载的概念

        在MyBatis中也称为懒加载,是指在进行表的关联查询时,不立即加载关联的对象,而是在真正使用到关联对象的数据时才执行查询。这种机制有助于提高应用程序的性能,尤其是在处理一对多或多对多关系时,可以避免不必要的查询,从而减少数据库的压力和内存的使用。

  1. 立即加载和延迟加载的区别,使用一对多的环境举例子。
  2. 立即加载:当前查询用户的时候,默认也把该用户所拥有的帐户信息查询出来了。
  3. 延迟加载:当前查询用户的时候,没有把该用户所拥有的帐户信息查询出来,而是使用帐户数据的时候,再去查询账户的数据。

2. 立即加载和延迟加载的应用场景

  1. 例如查询账户的时候,可以直接把用户查询出来,即查询多对一,这个时候可以选择立即加载。
  2. 例如查询用户的时候,可以先不查账号信息,等需要使用帐户信息的时候,再去查询,选择延迟加载。

3.举例

编写accountmapper

    <!-- 内连接的查询 -->
    <select id="findAll" resultMap="accountMap">
        SELECT * from account
    </select>
    
    <!-- 通过用户的id查询账户信息 -->
    <select id="findByUid" parameterType="int" resultType="account">
        select * from account where uid = #{uid}
    </select>
    
    <!-- 配置映射 -->
    <resultMap type="Account" id="accountMap">
        <id column="id" property="id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>
        <!-- 配置延迟加载 -->
        <association property="user" javaType="User" select="com.qcbyjy.mapper.UserMapper.findById" column="uid">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="birthday" property="birthday"/>
            <result column="sex" property="sex"/>
            <result column="addresss" property="addresss"/>
        </association>
    </resultMap>

UserMapper

    <select id="findById" parameterType="int" resultType="User">
        select * from user where id = #{id}
    </select>

修改配置

    <settings>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 将积极加载改为消极加载及按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

测试

@Test
public void testFindAll() throws Exception {
    // 调用方法
    List<Account> list = mapper.findAll();
    for (Account account : list) {
        System.out.println("开始...");
        System.out.println(account.getMoney());
        System.out.println("结束...");
        System.out.println();
    }
}

4、一对多举例

usermapper

    <!-- 一对多的查询 -->
    <select id="findAll" resultMap="userMap">
        select * from user
    </select>
    
    <!-- 数据封装 -->
    <resultMap type="user" id="userMap">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="birthday" property="birthday"/>
        <result column="sex" property="sex"/>
        <result column="addresss" property="addresss"/>
        <!-- 
            select=""           使用帐户的方法查询
            column="id"         使用id值去查询账户
        -->
        <collection property="accounts" ofType="Account" select="com.qcbyjy.mapper.AccountMapper.findByUid" column="id" >
            <id column="id" property="id"/>
            <result column="uid" property="uid"/>
            <result column="money" property="money"/>
        </collection>
    </resultMap>

accountmapper

    <!-- 通过用户的id查询账户信息 -->
    <select id="findByUid" parameterType="int" resultType="account">
        select * from account where uid = #{uid}
    </select>

开启延时加载

    <settings>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 将积极加载改为消极加载及按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

测试

     @Test
    public void testFindAll() throws Exception {
        // 调用方法
        List<User> list = mapper.findAll();
        for (User user : list) {
            System.out.println(user.getUsername());
            System.out.println(user.getAccounts());
            System.out.println("==============");
        }
    }

二、缓存

缓存的概念

  1. 缓存的概念

    1. 在内存中临时存储数据,速度快,可以减少数据库的访问次数。
    2. 经常需要查询,不经常修改的数据,不是特别重要的数据都适合于存储到缓存中。
  2. 缓存可以将数据保存在内存中,是互联网系统常常用到的。目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。缓存是在计算机内存上保存的数据,读取时无需再从磁盘读入,因此具备快速读取和使用的特点。

    和大多数持久化框架一样,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 只开启一级缓存。

MyBatis的一级缓存

MyBatis的一级缓存也是SqlSession的缓存。

SqlSession对象中维护了一个Map集合,用于存储相互的缓存数据。

查询的时候,先从SqlSession的缓存中查找,如果有,直接返回。如果没有,查询数据库。

证明一级缓存的存在,通过用户id查询2次,查看结果。

    /**
     * 测试一级缓存是否存在
     */
    @Test
    public void testFindById() {
        User user = mapper.findById(41);
        System.out.println(user);
        User user2 = mapper.findById(41);
        System.out.println(user2);
    }
  1. 一级缓存的原理分析

    1. 一级缓存底层使用的是Map集合,key存储的是执行的SQL语句,value存放的是查询的对象

    2. BaseExecutor类的152行源码地方先查询缓存,再查询数据库。

    3. 一级缓存的生命周期和SqlSession的生命周期相同,SqlSession对象关闭,一级缓存也会关闭。

      1. session.clearCache();调用该方法可以清空缓存
      2. 调用调用SqlSession的update、insert、delete、commit和close等方法的时候也会清空缓存。

二级缓存

        MyBatis 的二级缓存是一个跨 SqlSession 的共享缓存,它的作用范围是 namespace 级别的,可以被多个 SqlSession 共享。这意味着,只要是同一个接口里面的相同方法,都可以共享这个缓存。二级缓存的生命周期与应用同步,当 MyBatis 使用了二级缓存,并且相应的 Mapper 和 select 语句也配置使用了二级缓存,那么在执行 select 查询时,MyBatis 会先从二级缓存中取数据,其次才是一级缓存,最后才是数据库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值