MyBatis的一级缓存和二级缓存

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis的一级缓存和二级缓存相关的知识,希望对你有一定的参考价值。

文章目录

碰见了不懂,学学接着

还是提问:首先,什么是缓存?

缓存是什么?

缓存其实就是存储在内存中的临时数据,这里的数据量会比较小,一般来说,服务器的内存也是有限的,不可能将所有的数据都放到服务器的内存里面,所以, 只会把关键数据放到缓存中,缓存因为速度快,使用方便而广泛使用

缓存在数据库中对查询结果的保存,可以使用缓存,这样能减少跟数据库交互的次数,进而提高响应速度。

Mybatis提供的缓存

Mybatis也提供了对缓存的支持,分为一级缓存和二级缓存,可以通过下图和下表来理解:

一级缓存?

一级缓存是默认开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSession会话中2 个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空。

例如下面Mybatis的代码:

代码中所走的所有查询操作都会进行默认进行一级缓存,一旦关闭sqlSession会话,缓存则会刷新

//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);

//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

//5.调用实现类对象中的方法,接收结果
Student stu = new Student(4,"赵六",36);
Integer result = mapper.update(stu);

// 这中间所走的所有查询操作都会进行缓存,一旦关闭sqlSession会话,缓存则会刷新

//6.处理结果
System.out.println(result);

//7.释放资源
// 清除缓存
sqlSession.clearCache();
// 释放会话
sqlSession.close();
// 关闭流
is.close();

这样看也是不明显的,我们在mybatis 的配置文件中加入以下配置,开启sql日志,每一个sql代表请求了一次数据库,这样我们就可以根据sql来判断是否使用了缓存。

<settings>
    <!--标准的日志工厂实现类,打印sql日志-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

或者配置log4j输出日志

<!--配置LOG4J-->
<settings>
    <setting name="logImpl" value="log4j"/>
</settings>

我们查询两次:

//5.调用实现类对象中的方法,接收结果
Student stu = new Student(4,"赵六",36);
Integer result = mapper.update(stu);
System.out.println(stu);
Student stu2 = new Student(4,"赵六",36);
System.out.println(stu2);

我们可以看到控制台其实就执行了一次sql代码:

说明他默认一级缓存了

一级缓存什么时候过期?什么时候清空?

一级缓存无过期时间,只有生命周期
MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象,当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

二级缓存?

二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启,有2种方式配置二级缓存,缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;

开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找;

如下图二级缓存的工作原理图

什么时候存?

在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

注意:开启了二级缓存后,建议将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中。

怎么配置?

第一种配置:

单个mapper配置,主需要在需要开启二级缓存的mapper.xml文件中加入以下配置即可开启。

<!-- 开启单个mapper的二级缓存,也叫全局缓存-->
  <cache />

注意一定要加到xxMapper.xml的文件内,千万不要加到mybatis 的主配置文件里面了,会报错的,正确的配置位置如下图所示:

第二种配置:

所有的mapper都开启二级缓存,在mybatis.xml中加入以下配置即可

<!--配置LOG4J-->
<settings>
    <setting name="logImpl" value="log4j"/>
    <!--  开启所有mapper的二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

二级缓存什么时候过期?什么时候清空?

二级缓存的过期时间是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。

每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。

缓存注意事项:

另外,缓存还有以下几种情况需要注意

  1. 映射语句文件中的所有 select 语句的结果将会被缓存。

  2. 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。

  3. 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。

  4. 缓存不会定时进行刷新(也就是说,没有刷新间隔)。

  5. 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。

  6. 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

以上是关于MyBatis的一级缓存和二级缓存的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis一级缓存和二级缓存

mybatis二级缓存默认开启吗?

Mybaits 缓存

mybatis——一级缓存二级缓存

MyBatis一级缓存和二级缓存

Mybatis----缓存(一级缓存二级缓存)