Mybaits基础缓存
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybaits基础缓存相关的知识,希望对你有一定的参考价值。
1、缓存的设置与使用
在Mybaits的jar包中,所有的缓存都需要实现一个接口org.apache.ibatis.cache.Cache,它具有最基础的一个实现类PerpetualCache。除此之外,Mybaits还使用了装饰器模式,在decorators文件夹内有一些装饰器,在不改变原有对象的基础上,增强扩展其功能。
缓存实现类 | 描述 | 作用 | 装饰条件 |
---|---|---|---|
基本缓存 | 缓存基本实现类 | 默认是PerpetualCache,也可以自定义如RedisCache,EhCache等,具备基本功能的缓存类 | 无 |
LruCache | LRU策略的缓存 | 当缓存达到上限时,删除最近最少使用的缓存 | eviction=“LRU”(默认) |
FifoCache | FIFO策略的缓存 | 当缓存达到上限时,删掉最先入队的缓存 | eviction=“FIFO” |
SoftReference WeakReference | 待清理策略的缓存 | 通过JVM的软引用和弱引用来实现缓存,当JVM内存不足时,会自动清理掉这些缓存,基于SoftReference和WeakReference | eviction=“SOFT” eviction=“WEAK” |
LoggingCache | 带日志功能的缓存 | 比如输出缓存命中率 | 基本 |
SynchronizedCache | 同步缓存 | 基于Synchronized关键字实现,解决并发问题 | 基本 |
BlockingCache | 阻塞缓存 | 通过get/put方式中加锁,保证只有一个线程操作缓存,基于java重入锁实现 | block=true |
SeralizedCache | 支持序列化的缓存 | 将对象序列化后存到缓存中,取出时反序列化 | readOnly=false |
ScheduledCache | 定时调度的缓存 | 在进行get/put/remove/getSize等操作前,判断缓存时间是否超过了设置的最长缓存时间(默认是1小时),如果是则清空缓存,即每隔一段时间清空一次缓存 | <mapper>的<cache>标签的flushInterval不为空 |
TransactionalCache | 事务缓存 | 在二级缓存中使用,可一次存入多个缓存,移除多个缓存 | 在TransactionCacheManager中用Map维护对应关系。 |
这些装饰类的使用是在对应的表Mapper文件中,使用cache标签内部的参数进行设置。
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024" eviction="LRU" flushInterval="120000" readOnly="false"/>
2、一级缓存
一级缓存又叫本地缓存,默认开启,作用域是session(会话级别),这个session实际上是SQLSession,SQLSession有一个默认实现DefaultSqlSession,在DefaultSqlSession中,关键的属性有两个。
private final Configuration configuration;
private final Executor executor;
configuration是全局唯一的配置,所以只能在一个session中进行使用的一级缓存应该放Executor 中。
那么在BaseExecutor 中确实包含有缓存。
public abstract class BaseExecutor implements Executor {
private static final Log log = LogFactory.getLog(BaseExecutor.class);
protected Transaction transaction;
protected Executor wrapper;
protected ConcurrentLinkedQueue<BaseExecutor.DeferredLoad> deferredLoads;
protected PerpetualCache localCache;
protected PerpetualCache localOutputParameterCache;
protected Configuration configuration;
protected int queryStack;
private boolean closed;
因此,作为SQLSession的一个属性,一级缓存是不能跨session的,只能在一个session内进行读取。
一级缓存有缓存失效的情况,当同一个session内执行更新操作,一级缓存会失效,这时再去读取就会让缓存失效。
一级缓存有脏数据的问题,因为一级缓存不能跨session,所以当一个session有一级缓存,另一个session更新了对应数据后,就会导致第一个session内的缓存不知道数据已经被更新,导致出现脏数据。
除此之外,如果非要关闭一级缓存,可以在settings标签中设置。当localCacheScope设置为Session时代表作用域是session,设置为Statement时代表作用域是statement,也就起不到缓存效果,算是关闭了。
<setting name="localCacheScope" value="STATEMENT"/> //一级缓存不生效
<setting name="localCacheScope" value="SESSION"/> //一级缓存生效
3、二级缓存
二级缓存的作用域是namespace,namespace就是命名空间,mapper文件中有一个标签就是namepace,在这一个mapper文件下的所有语句共享一个命名空间,无论是不是一个SQLSession。
二级缓存的维护对象是CachingExecutor,因为二级缓存的作用范围大于一级缓存,所以查询时需要先命中二级缓存,再命中一级缓存,最后查询数据库。
在spring-mvc.xml文件的settings标签下,有一个内容,只有cacheEnabled设置为false时,二级缓存才不生效,无论是true还是不设置都是生效的。
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
想要二级缓存生效,还需要在对应的mapper的xml文件中增加标签
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024" eviction="LRU" flushInterval="120000" readOnly="false"/>
在这个标签中,每一个属性都有自己的配置:
- type:配置缓存类,除了自带的类,也可以设置第三方的类进行缓存,比如redis,EH
- size:缓存管理的key数量
- eviction:选用的缓存淘汰策略
- flushInterval:缓存对象存活时间
- readonly:是否只读。如果只读,则返回的都是同一个类。非只读,就需要实现序列化,因为mybaits会为缓存对象进行序列化和反序列化创造新的类。
这样,在这个namespace中,所有的select的结果都能被二级缓存进行缓存,更新等操作则会清除缓存。如果某一个select的结果不想被缓存,可以在select标签中增加属性
useCache="false"
<select id="queryUser" parameterType="java.lang.Long"
resultMap="BaseResultMap" useCache="false">
select
<include refid="Base_Column_List" />
from user
</select>
如果两个namespace想要共用一个二级缓存,可以在其中一个namespace中增加一个标签,cache-ref,这样就可以将共用缓存了。
<cache-ref namespace=""/>
以上是关于Mybaits基础缓存的主要内容,如果未能解决你的问题,请参考以下文章