Loading

【MyBatis】MyBatis 缓存

MyBatis 缓存

文章源码

什么是缓存

像大多数的持久化框架一样,MyBatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。

Mybatis 中缓存分为一级缓存,二级缓存。

缓存的适用范围

适用范围:

  • 经常查询并且不经常改变的
  • 数据的正确与否对最终结果影响不大

一级缓存

它指的是 MyBatis 中 SqlSession 对象的缓存,当执行查询之后,查询的结果会同时存入到 SqlSession 会提供一块区域。该区域的结构是一个 Map,当再次查询同样的数据,MyBatis 会先去 SqlSession 中查询是否存在,如果有则直接拿出来使用。

当 SqlSession 对象消失时,MyBatis 的一级缓存也就消失了。

一级缓存的使用

  • 编写用户持久层 DAO 接口

        /**
        * 根据 ID 查询操作,使用一级缓存
        * @param id
        * @return
        */
        User findByIdCache(Integer id);
    
  • 编写用户持久层映射文件

        <select id="findByIdCache" resultType="USER" parameterType="java.lang.Integer">
            select * from user where id = #{id};
        </select>
    
  • 测试

        @Test
        public void findByIdCacheTest() {
            User user1 = userDAO.findByIdCache(41);
            System.out.println(user1.hashCode());  // 1439337960
            User user2 = userDAO.findByIdCache(41);
            System.out.println(user2.hashCode());  // 1439337960
    
            System.out.println(user1 == user2); // true
        }
    

一级缓存的清空

    @Test
    public void findByIdCacheClearTest() {
        User user1 = userDAO.findByIdCache(41);
        System.out.println(user1.hashCode());  // 1439337960

        // 使缓存消失方法一:关闭 SqlSession 对象
        // session.close();

        // 使缓存消失方法二
        session.clearCache();

        // session = factory.openSession();
        userDAO = session.getMapper(UserDAO.class);

        User user2 = userDAO.findByIdCache(41);
        System.out.println(user2.hashCode());  // 315860201

        System.out.println(user1 == user2); // false
    }

一级缓存的分析

  • 一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit()close() 等方法时,就会清空一级缓存。
  • 第一次发起查询用户 id 为 41 的用户信息,先去找缓存中是否有 id 为 41 的用户信息,如果没有,从数据库查询用户信息。
  • 得到用户信息,将用户信息存储到一级缓存中。
  • 如果 SqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读
  • 第二次发起查询用户 id 为 41 的用户信息,先去找缓存中是否有 id 为 41 的用户信息,缓存中有,直接从缓存中获取用户信息。

二级缓存

它指的是 MyBatis 中 SqlSessionFactory 对象的缓存,由同一个 SqlSessionFactory 对象创建的 SqlSession 共享其缓存。

二级缓存结构图

二级缓存结构图

二级缓存的使用

  • 在 SqlMapConfig.xml 文件开启二级缓存

    <settings>
            <!-- 开启二级缓存的支持 -->
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
  • 配置相关的 Mapper 映射文件

        <!-- 开启二级缓存的支持 -->
        <cache></cache>
    
  • 配置 statement 上面的 useCache 属性

        <select id="findByIdHighCache" resultType="USER" parameterType="java.lang.Integer" useCache="true">
            select * from user where id = #{id};
        </select>
    
  • 测试

        @Test
        public void findByIdHighCacheTest() {
            SqlSession sqlSession1 = factory.openSession();
            UserDAO dao1 = sqlSession1.getMapper(UserDAO.class);
            User user1 = dao1.findByIdHighCache(41);
            System.out.println(user1.hashCode());   // 765284253
            sqlSession1.close();    // 一级缓存消失
    
            SqlSession sqlSession2 = factory.openSession();
            UserDAO dao2 = sqlSession2.getMapper(UserDAO.class);
            User user2 = dao2.findByIdHighCache(41);
            System.out.println(user2.hashCode());   // 1043351526
            sqlSession1.close();    // 一级缓存消失
    
            System.out.println(user1 == user2); // false
    
        }
    

测试中执行了两次查询,并且在执行第一次查询后,关闭了一级缓存,再去执行第二次查询时,可以发现并没有对数据库发出 SQL 语句,所以此时的数据就只能是来自于所说的二级缓存。

练习和总结

posted @ 2020-12-19 18:29  Parzulpan  阅读(63)  评论(0编辑  收藏  举报