MyBatis 详解(十)

发布于 2021-07-28  217 次阅读


缓存

什么是缓存(Cache)

  • 存在内存中的临时数据
  • 将用户经常查询的数据放在缓存(内存)中,用户去査询数据就不用从磁盘上(关系型数据库数据文件)查
    询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能可题。

为什么使用缓存

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

什么样的数据能使用缓存

  • 经常查询并且不经常改变的数据。

MyBatis 缓存

MyBatis 系统中默认定义了两级缓存:一级缓存二级缓存

  • 默认情况下,只有一级缓存开启。(SqlSession 级别的缓存,也称为本地缓存)
  • 二级缓存需要手动开启和配置,他是基于 namespace 级别的缓存。
  • 为了提高扩展性, MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存。

一级缓存

@Select("select * from user where id=#{id}")
User getUserById(@Param("id") int id);
@Test
public void userTest(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    UserMapper02 userMapper02 = sqlSession.getMapper(UserMapper02.class);
    User user = userMapper02.getUserById(1);
    System.out.println("====================");
    //sqlSession.clearCache();    //手动清理缓存
    User user02 = userMapper02.getUserById(1);
    System.out.println(user == user02);
    sqlSession.close();
}

MyBatis 详解(十)插图

可以从上图看出,getUserById 方法执行了两次,但是 sql 语句却只执行了一次,而且对象的引用地址也是一样的。这就说明第二次的查询是从缓存中取出来的。

但是缓存也有失效的情况:(也可以说是一开始就不存在)

  • 不在同一个 SqlSession 对象中
  • 查询参数不同
  • 増删改操作,可能会改变原来的数据,所以必定要刷新缓存。MyBatis 详解(十)插图1
  • 查询不同的 Mapper.xml
  • 手动清理缓存

二级缓存

一级缓存作用域太低了,所以诞生了二级缓存。一个会话查询数据,数据就会被放在当前会话的缓存中;如果当前会话关闭了,这个会话对应的一级缓存就没了;会话关闭了,一级缓存中的数据会被保存到二级缓存中。新的会话查询信息,就可以从二级缓存中获取内容。

User getUserById02(@Param("id") int id);
<?xml version="1.0" encoding="UTF-8" ?>
<!--UserMapper02.xml-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ml.guest997.mapper.UserMapper02">
    <!--配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
        可用的清除策略有:
        LRU – 最近最少使用:移除最长时间不被使用的对象。
        FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
        SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
        WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。-->
    <cache eviction="FIFO"
           flushInterval="60000"
           size="512"
           readOnly="true"/>
    <select id="getUserById02" resultType="user">
        select * from user where id=#{id}
    </select>
</mapper>
@Test
public void userTest02(){
    //创建两个 SqlSession 对象
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    SqlSession sqlSession02 = MyBatisUtil.getSqlSession();
    UserMapper02 userMapper02 = sqlSession.getMapper(UserMapper02.class);
    UserMapper02 userMapper022 = sqlSession02.getMapper(UserMapper02.class);

    User user = userMapper02.getUserById02(1);
    sqlSession.close();
    System.out.println("====================");
    User user02 = userMapper022.getUserById02(1);
    System.out.println(user == user02);
    sqlSession02.close();
}

MyBatis 详解(十)插图2

只有当会话提交或关闭时,才会转存到二级缓存中。用户查询数据时,会先从二级缓存中找,没有就到一级缓存中找,还是没有就会连接数据库执行 sql 语句。