MyBatis加载策略和缓存

什么是延迟加载?

  1. 延迟加载概念:延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
  2. 延迟加载优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
  3. 延迟加载缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
  4. 延迟加载的应用场景:在多表操作中,一对多,多对多:通常情况下采用延迟加载,一对一(多对一):通常情况下采用立即加载。
  5. 延迟加载是基于嵌套查询来实现的

局部延迟加载

  1. 在association和collection标签中都有一个fetchType属性,通过修改它的值,可以修改局部的加载策略。

    <!--一对一嵌套查询:查询所有订单,与此同时还要查询出每个订单所属的用户信息-->
    <resultMap id="orderMap2" type="com.code.entity.Orders">
        <id property="id" column="id"/>
        <result property="ordertime" column="ordertime"/>
        <result property="total" column="total"/>
        <result property="uid" column="uid"/>
        <!--fetchType="lazy" : 延迟加载策略
              fetchType="eager": 立即加载策略
          -->
        <!--问题:1.怎么去执行第二条sql , 2.如何执行第二条sql的时候,把uid作为参数进行传递-->
        <association property="user" javaType="com.code.entity.User"
                     select="com.code.mapper.UserMapper.findById" column="uid" fetchType="lazy"/>
    </resultMap>
    <!--一对一嵌套查询-->
    <select id="findAllWithUser2" resultMap="orderMap2">
        SELECT * FROM orders
    </select>
    
  2. 设置触发延迟加载的方法:在配置了延迟加载策略后,发现即使没有调用关联对象的任何方法,但是在调用当前对象的equals、clone、hashCode、toString方法时也会触发关联对象的查询。可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法。

    <settings>
    	<!--所有方法都会延迟加载-->
    	<setting name="lazyLoadTriggerMethods" value="toString()"/>
    </settings>
    

全局延迟加载

  1. 在Mybatis的核心配置文件中可以使用setting标签修改全局的加载策略

    <settings>
    	<!--开启全局延迟加载功能-->
    	<setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    
  2. 局部的加载策略优先级高于全局的加载策略。

    <!--一对一嵌套查询:查询所有订单,与此同时还要查询出每个订单所属的用户信息-->
    <resultMap id="orderMap2" type="com.code.entity.Orders">
        <id property="id" column="id"/>
        <result property="ordertime" column="ordertime"/>
        <result property="total" column="total"/>
        <result property="uid" column="uid"/>
        <!--fetchType="lazy" : 延迟加载策略
              fetchType="eager": 立即加载策略
          -->
        <!--问题:1.怎么去执行第二条sql , 2.如何执行第二条sql的时候,把uid作为参数进行传递-->
        <association property="user" javaType="com.code.entity.User"
                     select="com.code.mapper.UserMapper.findById" column="uid" fetchType="eager"/>
    </resultMap>
    <!--一对一嵌套查询-->
    <select id="findAllWithUser2" resultMap="orderMap2">
        SELECT * FROM orders
    </select>
    

MyBatis缓存

  1. 当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存中。当用户再次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询。
  2. 使用MyBatis缓存减少网络连接和数据库查询带来的损耗,从而提高查询效率,减少高并发访问带来的系统性能问题。
  3. 经常查询一些不经常发生变化的数据,使用缓存来提高查询效率。
  4. Mybatis提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。

一级缓存

  1. 一级缓存是SqlSession级别的缓存,是默认开启的。
  2. 在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
  3. 一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清空缓存。

在这里插入图片描述

  1. sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读

    /**
     * 验证mybatis中的一级缓存
     * @throws IOException
     */
    @Test
    public void testOneCache() throws IOException {
    
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
        // 根据id查询用户信息
        // 第一次查询,查询的数据库
        User user1 = userMapper.findById(1);
        System.out.println(user1);
    
        // clearCache: 手动清空缓存
        //sqlSession.clearCache();
    
        // 第二次查询,查询的是一级缓存
        User user2 = userMapper.findById(1);
        System.out.println(user2);
    
        sqlSession.close();
    
    }
    
  2. 在映射文件中配置 flushCache=“true”

    <!-- 每次查询时,都会清除缓存 -->
    < select flushCache="true"></select>
    

二级缓存

  1. 二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的

  2. 二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置 <cache/> 就可以开启二级缓存了。在这里插入图片描述

    <!--当前映射文件开启二级缓存-->
    <cache></cache>
    
  3. 配置核心配置文件

    <!--
     因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。
     为true代表开启二级缓存;为false代表不开启二级缓存。
     -->
    <setting name="cacheEnabled" value="true"/>
    
  4. 配置UserMapper.xml映射

    <!--
     <select>标签中设置useCache=true”代表当前这个statement要使用二级缓存。
     如果不使用二级缓存可以设置为false
     注意:
     针对每次查询都需要最新的数据sql,要设置成useCache="false",禁用二级缓存。
     -->
    <select id="findById" parameterType="int" resultType="user" useCache="true">
        SELECT * FROM `user` where id = #{id}
    </select>
    
  5. 二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。在这里插入图片描述

  6. 映射语句文件中的所有select语句将会被缓存。映射语句文件中的所有insert、update和delete语句会刷新缓存。

注意:

  1. mybatis的二级缓存因为是namespace级别,所以在进行多表查询时会产生脏读问题
  2. mybatis的缓存,都不需要我们手动存储和获取数据。mybatis自动维护的。
  3. mybatis开启了二级缓存后,那么查询顺序:二级缓存–》一级缓存–》数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值