MyBatis缓存

几乎所有的ORM框架都提供了缓存机制。

MyBatis框架包含了一个非常强大的缓存特征,它可以很方便的配置使用。实际开发中,缓存可以极大的提升查询的效率

MyBatis中的有两个缓存,一级缓存和二级缓存。默认情况下,只有一级缓存是开启的,一级缓存是SqlSession级别的缓存,二级缓存需要手动开启和配置,二级缓存是namespace级别的缓存

MyBatis中也提供了缓存接口,我们也可以整合第三方的二级缓存插件来使用,提高扩展性

一级缓存

一级缓存是SqlSession级别的缓存,共享范围就在一个SqlSession内。一级缓存默认就是存在的,我们只需要证明一下它的存在就可以了

@Test
    public void test4(){
        IUserMapper iUserMapper = sqlSession.getMapper(IUserMapper.class);
        User user = iUserMapper.findById(1);
        System.out.println(user);
//        sqlSession.clearCache();//手动清空缓存,清空和不清空的情况下运行一边就能看出不同

        User user2 = iUserMapper.findById(1);
        System.out.println(user2);
    }

1.首先使用同一个SqlSession执行了两个根据id查询,并且条件相同,这时就能发现MyBatis执行了一次查询数据库的操作:

spring cloud mybatis 开启二级缓存_mybatis

2.在执行第一个查询后,手动清空一下SqlSession中的缓存,虽然条件相同,但是还是会查询两次数据库

spring cloud mybatis 开启二级缓存_缓存_02

注意:

一级缓存是SqlSession级别的缓存,当SqlSession进行了增、删、改、commit、close操作时,就会清空一级缓存

二级缓存

二级缓存是同一个命名空间(namespace)级别的缓存,它们有一个共同cache。也就是二级缓存可以被多个SqlSession共享。

在mybatis-config.xml文件中开启二级缓存

<settings>
<!--        开启二级缓存,默认就是开启,可以忽略-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

在mapper映射文件中加入一个cache标签:

<!--    表示这个mapper中查询的结果都会保存到二级缓存-->
    <cache/>

没有特殊需求时,写一个< cache/>标签即可,如果有需要可以根据其中的属性进行配置

cache标签中的属性:

  • eviction:缓存回收策略:
  • LRU:移除最长时间不用的对象
  • FIFO:根据对象进入缓存的顺序来移除对象,先进先出
  • SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
  • WEAK:弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
  • flushinterval:缓存的刷新间隔,毫秒值。默认为不刷新
  • readOnly:是否为只读,true为只读,false读写(默认)
  • size:存放元素的个数
  • type:指定自定义缓存的全类名
  • blocking:设置缓存中找不到对应key是否一直blocking,直到有对应数据进入缓存

在mapper映射文件中准备一个开启二级缓存的sql:

<!--                               useCache为true,表示这个Statement会使用二级缓存-->
    <select id="findById" parameterType="int" resultType="User" useCache="true">
        select * from t_user where id=#{id}
    </select>

POJO类:

使用MyBatis中的二级缓存时,所缓存的对象一定要实现序列化接口Serializable

public class User implements Serializable {
    private static final long serialVersionUID = 3800957211972451743L;
    private Integer id;
    private String username;
    private String password;
    private String email;
    private String remark;
}

测试:
创建两个不同的SqlSession对象,都去查询同一个数据,findById(1)

@Test
    public void test4(){
        SqlSession sqlSession1 = factory.openSession();
        IUserMapper iUserMapper = sqlSession1.getMapper(IUserMapper.class);
        User user1 = iUserMapper.findById(1);
        System.out.println("--------------------------"+user1);
        sqlSession1.commit();
        sqlSession1.close();

        SqlSession sqlSession2 = factory.openSession();
        IUserMapper iUserMapper2 = sqlSession2.getMapper(IUserMapper.class);
        User user2 = iUserMapper2.findById(1);
        System.out.println("--------------------------"+user2);
    }

查看结果:

spring cloud mybatis 开启二级缓存_编程语言_03

补充:

  • 二级缓存是以namespace为单位的,不同的namespace中的操作互不影响
  • 多表查询的时候不要使用二级缓存,因为在不同的namespace中更新了其中一个表中的数据,一定会发生脏读,使用cache-ref来进行namespace的依赖也可以避免这种情况的发生
  • 二级缓存是表级缓存,开销大,一级缓存是使用HashMap存储,效率更高
  • 二级缓存在实际开发中其实并不常用,我们可以使用一些缓存插件,或者将缓存工作交给其他框架处理