Mybatis一二级缓存的使用和实现原理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Mybatis一二级缓存的使用和实现原理
概述
针对查询操作,mybatis支持通过缓存的方式来减少SQL的调用,提高查询性能。
在缓存级别方面分为一级缓存和二级缓存,
1. 一级缓存的粒度较小,是与某个SqlSession绑定的,只对该SqlSession的相关查询操作进行缓存,不同SqlSession实例之间相互不影响,缓存为使用本地内存实现;
2. 二级缓存是一种全局缓存,是由所有SqlSession实例所共享的,即不同SqlSession实例查询时产生的缓存,对其他SqlSession实例可见。
一级缓存
l mybatis的一级缓存支持两种缓存级别,分别是SESSION和STATEMENT,默认的一级缓存级别为SESSION。
l mybatis的一级缓存是默认开启的。
l 一级缓存的使用示意图如下:(图片引用自:mybatis一级缓存二级缓存)
SESSION级别
l 对该SqlSession实例发起的查询操作进行缓存,即由同一SqlSession实例发起的多次相同(SQL和SQL的参数值都相同)的查询操作,第一次是查询数据库,后续则查询缓存;但是如果另外一个SqlSession实例进行相同的查询操作,则需要进行数据库查询。
l 针对更新操作,如果是该SqlSession自身进行了更新操作,则
该SqlSession对应的一级缓存会被清空,但是如果是其他SqlSession 实例进行了更新操作,则此更新操作对该SqlSession不可见,所以该SqlSession的缓存数据是过期失效数据,所以SqlSession实例的生命周期不能过长,否则可能出现数据不一致现象。
STATEMENT级别
l 该级别是指缓存只针对当前执行的查询语句有效,故每次语句执行完之后都会清空缓存,其实是相当于没有缓存,即该sqlSession 实例下次调用相同的SQL语句和相同参数值时,由于上一次语句执行后,缓存被清空了,故需要继续查询数据库。
具体可以看源码的query实现:
配置方法
l mybatis的一级缓存是内部实现的一个特性,用户不能配置,默
认情况下为开启的。
同时内部也是使用一个基于HashMap实现的本地内存来实现,故在配置方面只能配置缓存级别为STATEMENT来关闭一级缓存。
配置主要是在全局配置mybatisConfig.xml中配置,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN"
"/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="localCacheScope" value="STATEMENT"/> ...
</settings>
...
</configuration>
二级缓存
l mybatis默认没有开启二级缓存,二级缓存支持在配置中自定义底层所用的缓存实现,包括使用本地内存和分布式缓存。
l 二级缓存是基于namespace的,即作用域为mapper,故需要在每个mapper中配置自身所使用的二级缓存实现以及缓存策略。
同时由于二级缓存是基于namespace的,所以不同namespace之间的相互不影响的,如一个namespace使用的本地内存,另外一个namespace使用的是分布式缓存,则如果不同namespace对同一张数据表的数据进行了操作,则可能会存在数据不一致问题。
l 如果二级缓存使用本地内存的话,则由于开启二级缓存之后,需要在本地内存缓存大量的数据,即对所有SqlSession实例的查询进行缓存,故可能造成内存资源的开销较大。
l 二级缓存的使用示意图如下:(图片引用自:mybatis一级缓存
二级缓存)
配置方法
l 二级缓存的配置分为三步:
1.首先在mybatisConfig.xml文件中配置全局开关的:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN"
"/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true" />
...
</settings>
...
</configuration>
2.然后需要在各个mapper对应的配置文件mapper.xml中配置
cache标签,可以指定该mapper使用的二级缓存的底层实现和相关缓存配置等。
cache标签也可以是空标签,则使用默认的基于本地内存的二级缓存实现。
<mapper namespace="erdao">
<!-- Cache 配置-->
<!-- <cache /> -->
<!-- <cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true" /> -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache" /> </mapper>
3.这步是可选的,即在mapper内部的每个select可以通过useCache开关来控制当前查询select是否使用二级缓存:默认为true。
<select id="selectBlog"
resultMap="BaseResultMap"
parameterType="ng.Long"
useCache="false">
...
</select>
总结
l 由以上分析可知,虽然一级和二级缓存的使用可以减少数据库查询操作,但是都存在造成数据不一致的情况存在:对于一级缓存由于不同sqlSession实例之间相互隔离,则可能出现其中一个更新了数据库数据,但是另外一个由于使用了自身内部的缓存,故读取到失效的旧数据;对于二级缓存,由所有sqlSession实例共享,基于namespace隔离,故如果不同namespace定义了同时操作一个表的
SQL语句,则会造成不同namespace之间的缓存不一致问题。
所以如果对于mybatis的内部运作机制不理解,可能会由于这些造成数据不一致的情况存在,则可能会导致莫名其妙的问题。
l 针对以上这些问题,建议统一使用额外的缓存实现,即在应用代码中自定义缓存实现,关闭mybatis的一级和二级缓存,只使用mybatis基于SQL来进行数据库操作。