说到Mybatis的缓存机制之前,我们先来说一说缓存。
缓存
缓存的引出
拿我们的查询作为例子:我们的数据库查询需要连接数据库,这意味着消耗资源。那如果我们使用同一条语句多次查询,这就会多次获取数据库连接,关闭连接,非常消耗数据库资源,我们设想一下,如果我们一次查询的结果,给他暂存到一个可以直接拿到的地方,那么我们就不用走数据库了!
所以我们就要使用到缓存!
什么是缓存
所谓缓存Cache,我们可以从下面的定义来看
- 缓存是存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库的数据文件中)去查询,从缓存中查询,从而提供查询效率,解决了高并发系统的性能问题
为什么要使用缓存
- 减少和数据库的交换次数,减少系统开销,提供系统效率,解决高并发系统的性能问题。
什么样的数据要使用到缓存
- 经常查询并且不经常改变的数据要使用到缓存
说完缓存,我们接下来说说Mybaits的缓存机制。
Mybatis的缓存机制
Mybatis包含一个很强大的查询缓存机制,它可以极大的提升查询效率。
Mybatis框架中默认定义了两极缓存
一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(一级缓存是sqlSession基本的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置(二级缓存是基于namespace级别的缓存,也称为全局缓存)
效果如下:
- 映射文件中的所有select语句的结果将会被缓存
- 映射语句文件中的所有insert、update和delete语句会刷新缓存
- 缓存不会定时进行刷新,但是缓存会使用最近最少使用算法(LRU)来清除不需要的缓存(去了解下LRU)
Mybatis中的一级缓存
现在来说说Mybatis中的一级缓存
一级缓存:从sqlSession被创建出来开始,一级缓存开始生效,而知道sqlSeesion.close()方法被调用返回到池子中,一级缓存才失效。Mybatis中从SQLSession被创建到返回池子的这个过程叫一级缓存。
一级缓存是基于SQLSession基本的,也被称为本地缓存。一级缓存是Mybatis默认开启的缓存,也关不掉,只有在一次SQLSession中有效。这个一级缓存相当于一个Map,用的时候就去取出来。
一级缓存失效的情况
- 增删改操作,可能会改变原来的数据,所有一定会刷新缓存
- 查询不同的东西也会刷新缓存
- 查询不同的Mapper.xml
- 手动清理缓存 sqlSession.clearCache()
Mybatis中的二级缓存
为什么会出现二级缓存,原因是因为一级缓存是基于sqlSession级别的,作用域太低了,所以就诞生了二级缓存。
二级缓存:Mybatis中的二级缓存是基于namespace的缓存,一个命名空间对应一个二级缓存。
使用二级缓存的步骤
- 首先需要Mybatis的全局配置文件中显示的开启全局缓存
<settings>
<!--显示的开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
- 在要使用二级缓存的Mapper.xml中开启
<!--在需要开启二级缓存的Mapper中开启!-->
<cache/>
Mybatis中的二级缓存的工作机制
- 一个会话(sqlSession)查询的一条数据,这个数据会被放在当前会话(sqlSession)的一级缓存中
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
- 新的会话信息查询,就可以先从二级缓存中查询
- 不同的mapper查出的数据会放在自己对应的缓存中
使用总的缓存顺序是:
- 先看二级缓存中有没有
- 再看一级缓存中有没有
- 一二级都没有再查询数据库
总结
我们在开发中并不会使用Mybatis的二级或者自定义缓存,因为在分布式环境下,由于默认的Mybatis缓存实现本部都是基于本地的,然而Mybatis在多表查询是,极大肯会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻,而且在分布式环境下必然会出现读取到脏数据,需要使用集中式缓存来实现,有很大的开发成本,直接使用REDIS/Memcache等分布式缓存的成本耕地,安全性也越高。