一 缓存机制
MyBatis 包含一个非常强大的查询缓存
特性,它可以非常方便地配置
和定制
。缓存可以极大的提升查询效率
。
MyBatis系统中默认定义了两级缓存。一级缓存和二级缓存
。
– 1、默认情况下,只有一级缓存(SqlSession
级别的缓存,也称为本地缓存
)开启。
– 2、二级缓存需要手动
开启和配置,他是基于namespace级别
的缓存。
– 3、为了提高扩展性。 MyBatis定义了缓存接口Cache
。我们可以通过实现Cache接口来自定义二级缓存
架构图

二 一级缓存
一级缓存是sqlSession级别
的缓存。在操作数据库时需要构造sqlSession对象
,在对象中有一个数据结构(HashMap)
,用于存储缓存数据
。不同的sqlSession之间的缓存区域(HashMap)是互不影响
的。
一级缓存(local cache), 即本地缓存, 作用域默认为sqlSession
。当 Session flush
或 close
后, 该Session 中的所有 Cache 将被清空
。
• 本地缓存不能被关闭
, 但可以调用clearCache()
来清空本地缓存, 或者改变缓存的作用域
.
• 在mybatis3.1
之后, 可以配置本地缓存的作用域.
在 mybatis.xml 中配置
两种级别
Mybatis提供了一级缓存的方案来优化在数据库会话间重复查询的问题。实现的方式是每一个SqlSession中都持有了自己的缓存,一种是SESSION级别
,即在一个Mybatis会话
中执行的所有语句,都会共享这一个缓存。一种是STATEMENT
级别,可以理解为缓存只对当前执行的这一个statement有
效。Statement,即不使用一级缓存
。
工作流程
根据一级缓存的工作流程,我们绘制出一级缓存执行的时序图,如下图所示。

主要步骤如下:
- 对于某个
Select Statement
,根据该Statement生成key
。 - 判断在
Local Cache中
,该key是否用对应的数据存在。 - 如果命中,则跳过查询数据库,继续往下走。
- 如果没命中:
4.1 去数据库中查询数据,得到查询结果;
4.2 将key和查询到的结果作为key和value,放入Local Cache中。
4.3. 将查询结果返回; -
判断缓存级别是否为
STATEMENT`级别,如果是的话,清空本地缓存。
工作场景

(1). 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息
存储到一级缓存
中。(2). 如果sqlSession去执行commit操作(执行插入、更新、删除),
清空SqlSession中的一级缓存
,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。(3). 第二次发起查询用户id为1的用户信息,
先去找缓存`中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。mybatis默认支持一级缓存的。测试很简单,这里就不贴代码了。
三 二级缓存
• 二级缓存(second level cache
),全局作用域缓存
• 二级缓存默认不开启
,需要手动配置
• MyBatis提供二级缓存的接口以及实现
,缓存实现要求;POJO实现Serializable接口
• 二级缓存
在 SqlSession 关闭或提交
之后才会生效
使用步骤
– 1、全局配置文件中开启二级缓存
• <setting name="cacheEnabled" value="true"/>
– 2、需要使用二级缓存的映射文件
处使用cache配置缓存
或cache-ref
:cache-ref代表引用别的命名空间的Cache
配置,两个命名空间的操作使用的是同一个Cache
。
• <cache />
– 3、注意:POJO需要实现Serializable接口
映射文件的缓存配置
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
<cache-ref namespace="mapper.StudentMapper"/>
属性
-
eviction
:缓存的回收策略:
•LRU
– 最近最少使用的:移除最长时间不被使用的对象。
• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
• 默认的是LRU
。 -
flushInterval
:缓存刷新间隔
缓存多长时间清空一次,默认不清空,设置一个毫秒值 -
readOnly
:是否只读:
true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
mybatis为了加快获取速度,直接就会将数据在缓存中的引用
交给用户。不安全,速度快
false:非只读:mybatis觉得获取的数据可能会被修改。
mybatis会利用序列化&反序列的技术克隆
一份新的数据给你。安全,速度慢
-
size
:缓存存放多少元素; -
type
:指定自定义缓存的全类名;实现Cache接口即可; -
blocking
: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存
流程
当开启二级缓存后,会使用CachingExecutor装饰Executor,在进入后续执行前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

在二级缓存的使用中,一个namespace下的所有操作语句,都影响着同一个
Cache
,即二级缓存是被多个SqlSession共享着的,是一个全局的变量
。当开启缓存后,数据的查询执行的流程就是
二级缓存
-> 一级缓存
-> 数据库
。
不同namespace
查出的数据会放在自己对应
的缓存中(map)
效果:数据会从二级缓存中获取
- 查出的数据都会被默认先放在一级缓存中。
- 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
和缓存有关的设置/属性
- 每个select标签都有
useCache="true"
:false:不使用缓存(一级缓存依然使用
,二级缓存不使用) - 每个增删改标签的:flushCache="true":(一级二级都会清除):
增删改
执行完成后就会清除缓存
;
测试:flushCache="true"
:一级缓存就清空了;二级也
会被清除;
查询标签
:flushCache="false":
如果flushCache=true;每次查询之后都会清空缓存
;缓存是没有
被使用的
网友评论