23、mybatis学习——mybatis的二级缓存

MyBatis 一级缓存最大的共享范围就是一个SqlSession内部,那么如果多个 SqlSession 需要共享缓存,则需要开启二级缓存,开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示

 当二级缓存开启后,同一个命名空间(namespace) 所有的操作语句,都影响着一个共同的 cache,也就是二级缓存被多个 SqlSession 共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

二级缓存开启条件

二级缓存默认是不开启的,需要手动开启二级缓存,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。开启二级缓存的条件也是比较简单,通过直接在 MyBatis 配置文件中通过

<settings>
    <setting name = "cacheEnabled" value = "true" />
</settings>

来开启二级缓存,③还需要在 Mapper 的xml 配置文件中加入 <cache>标签

设置 cache 标签的属性

cache 标签有多个属性

  • eviction: 缓存回收策略,有这几种回收策略
    • LRU - 最近最少回收,移除最长时间不被使用的对象(默认)
    • FIFO - 先进先出,按照缓存进入的顺序来移除它们
    • SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
    • WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
  • flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
  • readOnly: 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改
  • size : 缓存存放多少个元素
  • type: 指定自定义缓存的全类名(实现Cache 接口即可)
  • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

举例:

Student.java(实现了序列化接口)

StudentMapper接口和StudentMapper.xml

 mybatis全局配置文件中开启二级缓存

 在StudentMapper.xml开启二级缓存

<!-- namespace中开启二级缓存
            eviction:缓存的回收策略(默认是LRU)
                LRU - 最近最少回收,移除最长时间不被使用的对象
                FIFO - 先进先出,按照缓存进入的顺序来移除它们
                SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
                WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象 
            flushInterval:缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
            readOnly:是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。
                    false 非只读(默认):MyBatis觉得获得的数据可能会被修改;mybatis会利用序列化&反序列化的技术克隆一份新的数据给你;安全,速度稍慢
            size:缓存存放多少个元素
            type: 指定自定义缓存的全类名(实现Cache接口即可)
            blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
            -->
            
     <cache eviction="LRU" flushInterval="60000" readOnly="false"></cache>

测试方法

    //测试二级缓存
    @Test
    public void testSecondLevelCache() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //两个会话
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        
        StudentMapper studentMapper1 = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
        
        //会话1关闭,此时student1从一级缓存转移到二级缓存
        Student student1 = studentMapper1.getStuById(1);
        sqlSession1.close();
        
        //会话2查询id为1的student,二级缓存中有,直接取出   
        Student student2 = studentMapper2.getStuById(1);
        sqlSession2.close();
        
        //student2从二级缓存中取出时,若<cache>中的属性readeronly为true
        //则这个输出true,若为false则这里输出false
        System.out.println(student1==student2);
    }

测试结果

此时在StudentMapper.xml中修改配置增加一个useCache="false"(<select>标签中才有的属性)

则此条查询语句不使用二级缓存;及时全局配置文件和当前namespace配置文件开启了二级缓存

同样进行测试

总结:

和二级缓存有关的设置/属性:
1、需要使用二级缓存的POJO实现序列化接口Serializable
2、<setting name="cacheEnabled" value="true"/>
3、<cache></cache>
4、<select>标签中的useCache属性
5、mapper.xml中的每一个增删改标签中的flushCache属性,默认为true;执行了增删改操作(一级和二级缓存都会清空)

 

posted @ 2020-02-26 00:10  Arbitrary233  阅读(240)  评论(0编辑  收藏  举报