Mybatis学习(五)Mybatis缓存

Mybatis 默认配置了两种缓存:
本地缓存(local cache)和二级缓存(second level cache)。

本地缓存

一直开启
开启时机:
每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。

生存周期:
同一会话时间

缓存的内容:
任何在 session 执行过的查询语句本身都会被保存在本地缓存中,那么,相同的查询语句和相同的参数所产生的更改就不会二度影响数据库了。

失效时机:
本地缓存会被增删改、提交事务、关闭事务以及关闭 session 所清空。
1)sqlsession不同
2)sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
3)sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
4)sqlSession相同,手动清除了一级缓存(缓存清空)sqlSession.clearCache()

默认情况下,本地缓存数据可在整个 session 的周期内使用,
这一缓存需要被用来解决循环引用错误和加快重复嵌套查询的速度,
所以它可以不被禁用掉,
但是你可以设置 localCacheScope=STATEMENT 表示缓存仅在语句执行时有效。

注意,如果 localCacheScope 被设置为 SESSION,
那么 MyBatis 所返回的引用将传递给保存在本地缓存里的相同对象。
对返回的对象(例如 list)做出任何更新将会影响本地缓存的内容,
进而影响存活在 session 生命周期中的缓存所返回的值。
因此,不要对 MyBatis 所返回的对象作出更改,以防后患。

你可以随时调用以下方法来清空本地缓存:

void clearCache()

这里写图片描述
一级缓存是 SqlSession 级别的缓存,是基于 HashMap 的本地缓存。
默认开启一级缓存。

二级缓存

基于nameSpace
工作机制:
一个会话在查询时,该数据会放在当前会话的一级会话,会话关闭,一级缓存放入二级缓存,新的查询信息按照二级缓存
查出来之后放入自己的一级缓存,会话关闭之后,转入二级缓存

二级缓存是 mapper 级别的缓存,同样是基于 HashMap 进行存储,多个 SqlSession 可以共用二级缓存,其作用域是 mapper 的同一个 namespace。不同的 SqlSession 两次执行相同的 namespace 下的 sql 语句,会执行相同的 sql,第二次查询只会查询第一次查询时读取数据库后写到缓存的数据,不会再去数据库查询。

二级缓存的配置

MyBatis 默认没有开启二级缓存,开启只需在配置文件中写入如下代码:
step1:在全局配置文件中开启

<settings>  
      <setting name="cacheEnabled" value="true"/>  
</settings>

step2:在映射文件mapper.xml里如下配置

<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"></cache>

说明:
eviction:缓存的回收策略:
• LRU – 最近最少使用的:移除最长时间不被使用的对象。
• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
• 默认的是 LRU。

flushInterval:缓存刷新间隔
缓存多长时间清空一次,默认不清空,设置一个毫秒值

readOnly:是否只读:
true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
false:非只读:mybatis觉得获取的数据可能会被修改。
mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢

    size:缓存存放多少元素; 
    type="":指定自定义缓存的全类名; 实现Cache接口即可;

step3:对应的POJO需要实现序列化接口

和缓存有关的设置/属性:

1)、cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)  
2)、每个select标签都有useCache="true": 
 false:不使用缓存(一级缓存依然使用,二级缓存不使用) 
3)、【每个增删改标签的:flushCache="true":(一级二级都会清除)】 
 增删改执行完成后就会清楚缓存; 
 测试:flushCache="true":一级缓存就清空了;二级也会被清除; 
 查询标签:flushCache="false": 
 如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的; 
 4)、sqlSession.clearCache();只是清除当前session的一级缓存; 
 5)、localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在会话缓存中; 
STATEMENT:可以禁用一级缓存;

myBatis实行sql的顺序:

查找二级缓存->一级缓存->数据库

一级缓存的源码实现

执行查询时,SqlSession交给Excutor来完成对数据库的各种操作。
Excutor的实现类BaseExcutor

BaseExecutor中拥有一个PerpetualCache,它是Cache接口的实现,则对于BaseExecutor对象而言,它将使用PerpetualCache对象维护缓存,Cache是一个缓存接口。

PerpetualCache是如何实现对缓存的维护的?通过一个HashMap维护查询结果

到这里,cacheKey的构建终于真相大白:根据 statementId 、 rowBounds 、传递给JDBC的SQL 和 rowBounds.limit决定key中的hashcode。因此,相同的操作就会有相同的hashcode,来保证一个cacheKey对应一个操作。

之前说一级缓存是Executor执行操作时会去PerpetualCache中的HashMap中根据cacheKey查询缓存。createCacheKey 还有update方法

mybatis下的cache包
CacheKey
NullCacheKey
TransactionalCacheManager

PerpetualCache拥有一个id内部维护了一个map equals方法值的学习

public boolean equals(Object o) {
        if (this.getId() == null) {
            throw new CacheException("Cache instances require an ID.");
        } else if (this == o) {
            return true;
        } else if (!(o instanceof Cache)) {
            return false;
        } else {
            Cache otherCache = (Cache)o;
            return this.getId().equals(otherCache.getId());
        }
    }

二级缓存的源码实现

二级缓存的原理SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,然后将操作数据库的任务交给CachingExecutor,此时CachingExecutor会查找二级缓存是否有需要的数据,如果没有则将任务交给Executor对象。
CachingExecutor包装了Executor接口

Configration中。
各种各样的cache
BlockingCache
FifoCache
LoggingCache
LruCache
ScheduledCache
SerializedCache
SoftCache
SynchronizedCache
TransactionalCache
WeakCache

mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。

mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。

mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.1</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.0.0</version>
</dependency>

二级缓存的应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度

业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。

实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

二级缓存局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,对同时缓存较多条数据的缓存,

比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。

解决此类问题需要在业务层根据需求对数据有针对性缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值