mybatis内置二级缓存

在mybatis中有两种二级缓存,一种是内置的一种是外置的。myBatis 查询缓存的作用域是根据映射文件 mapper 的 namespace 划分的,相同namespace 的 mapper 查询数据存放在同一个缓存区域。不同 namespace 下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照 namespace 进行分别存放的。

内置二级缓存

myBatis 内置的二级缓存为 org.apache.ibatis.cache.impl.PerpetualCache。与一级缓存不同的是二级缓存的生命周期会与整个应用同步,与sqlSession是否关闭没有关系。二级缓存的使用比较简单,只需对之前的程序稍作修改即可。

序列化javabean
将javabean实现Serializable接口,如果该javabean有显示的父类的话,让父类也实现Serializable接口。

cache标签
在mapper配置文件中的mapper标签下添加下面标签:

<cache/>

在上面的标签中有一些属性,通过配置这些属性可以调整一些参数

  • eviction:逐出策略。当二级缓存中的对象达到最大值时,就需要通过逐出策略将缓存中的对象移出缓存。默认为 LRU。常用的策略有:
    • FIFO:First In First Out,先进先出
    • LRU:Least Recently Used,未被使用时间最长的
  • flushInterval:刷新缓存的时间间隔,单位毫秒。这里的刷新缓存即清空缓存。一般不指定,即当执行增删改时刷新缓存,如果长时间未刷新缓存有肯能会出现过期数据。
  • readOnly:设置缓存中数据是否只读。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改的,这样性能会好一些,缺点是因为他是只读的,所以不能被修改。如果设置为false的话,读写的缓存会通过序列化返回该缓存对象的拷贝,因为会把对象进行拷贝,这会慢一些,但是安全,因此默认是 false。
  • size:二级缓存中可以存放的最多对象个数。默认为 1024 个。

验证内置二级缓存

二级缓存的声明周期会与整个应用同步,而一级缓存只在sqlSession域中有效,此时需要将测试代码修改如下,将sqlSession关闭,让一级缓存失效,从而验证二级缓存的存在。

@Test
public void selectStudentById(){
    Student student1 = studentDao.selectStudentById(2);
    System.out.println(student1);

    //关闭sqlSession
    this.sqlSession.close();

    //重新获取sqlSession对象
    sqlSession = MyBatisUtil.getSqlSession();
    //通过该方法可以获取StudentDao的对象
    studentDao = sqlSession.getMapper(StudentDao.class);

    //二级缓存开启后,这部分将不会发出sql语句查询数据库,而是从缓存中获取数据
    Student student2 = studentDao.selectStudentById(2);
    System.out.println(student2);
}

上面程序执行后,可以看到控制台中只发出了一条sql语句,这样就验证了二级缓存的存在。

增删改对二级缓存的影响
增删改操作,无论是否进行提交commit(),均会清空一级、二级查询缓存,使查询再次从DB中select。
这里的二级缓存中的key是不会清空,只清空key对应的值。

如果想要设置增删改操作的时候不清空二级缓存的话,可以在其insert或delete或update中添加属性flushCache=”false”,默认为 true。

<delete id="deleteStudent" flushCache="false">
    DELETE FROM t_student where id=#{id}
</delete>

二级缓存的关闭

根据关闭的范围大小,可以分为全局关闭与局部关闭。

  • 全局关闭
    全局关闭是将整个应用的二级缓存全部关闭,所有查询均不使用二级缓存。全局开关设置在mybatis.xml配置文件的全局设置中,将属性cacheEnabled设置为 false,则关闭;设置为 true,则开启,默认值为 true。即二级缓存默认是开启的。
<setting name="cacheEnabled" value="false"/>
  • 局部关闭
    局部关闭是只关闭某个select查询的二级缓存,在select标签中将属性useCache设置为false,那么就会关闭该select查询的二级缓存。
<select id="selectStudentById" useCache="false" resultMap="studentMapper">
    SELECT id,name,age,score,password FROM t_student where id=#{id}
</select>

二级缓存的使用注意事项

  • 在一个命名空间下使用二级缓存
    二级缓存对于不同的命名空间namespace的数据是互不干扰的,倘若多个namespace中对一个表进行操作的话,就会导致这不同的namespace中的数据不一致的情况。

  • 在单表上使用二级缓存
    在做关联关系查询时,就会发生多表的操作,此时有可能这些表存在于多个namespace中,这就会出现上一条内容出现的问题了。

  • 查询多于修改时使用二级缓存
    在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。