二级缓存与一级缓存机制相同,不同的是它的作用域是在Mapper层, 即不同会话之间共享缓存内容,二级缓存不是默认开启的,如果配置了cache功能在创建Executor后会装饰一层CachingExecutor,存取二级缓存都在CachingExecutor中封装,总体缓存架构图见https://my.oschina.net/chengxiaoyuan/blog/792878
一、二级缓存使用
全局配置
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
Mapper里面配置cache
<mapper namespace="com.domain.CachedAuthorMapper">
<cache />
</mapper>
如果想mapper中某个查询不用二级缓存则配置useCache=“false”
<select id="selectAllAuthors" resultType="domain.blog.Author" useCache="false">
如果希望每次执行sql前都刷新缓存则配置flushCache="true",该值select类型默认为false, 其他为true
二、二级缓存构造
上面cache里面有几个参数配置:
public class XMLMapperBuilder extends BaseBuilder {
private void cacheElement(XNode context) throws Exception {
if (context != null) {
//获取缓存类型, 默认内存map, PERPETUAL在configuration初始化的时候会注册对应PerpetualCache
String type = context.getStringAttribute("type", "PERPETUAL");
//获取class,如果该类型不是自带的会使用classLoader加载
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
//回收策略,装饰上面的缓存, 默认LRU
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
//标签下面的参数
Properties props = context.getChildrenAsProperties();
//通过上面的参数构造cache
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props);
}
}
}
PERPETUAL、LRU这些简称在初始化的时候会注册:
public Configuration() {
.......
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
......
}
上面去的各种参数后通过builderAssistant构造缓存并放到configuration配置的map中,看builderAssistant.useNewCache代码:
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval,
Integer size, boolean readWrite, Properties props) {
//判断为空则取默认
typeClass = valueOrDefault(typeClass, PerpetualCache.class);
evictionClass = valueOrDefault(evictionClass, LruCache.class);
//创建cache, 这里是builder模式, currentNamespace为id
Cache cache = new CacheBuilder(currentNamespace).implementation(typeClass).addDecorator(evictionClass)
.clearInterval(flushInterval).size(size).readWrite(readWrite).properties(props).build();
//放到configuration里的map中, key为cache的id
configuration.addCache(cache);
currentCache = cache;
return cache;
}
最终通过缓存的构造模式构造一个缓存,并把缓存放入到configuration的map中,看CacheBuilder
public Cache build() {
//判断缓存内部实现和装饰是否为空,如果为空则再给默认值
setDefaultImplementations();
//创建缓存实现
Cache cache = newBaseCacheInstance(implementation, id);
//properties配置
setCacheProperties(cache);
//如果是内部map缓存则用内部装饰
if (PerpetualCache.class.equals(cache.getClass())) {
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
//如果是LoggingCache子类则用LoggingCache装饰
cache = new LoggingCache(cache);
}
return cache;
}
三、接入第三方缓存
导入依赖包
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.2</version>
</dependency>
ehcache自带配置
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
</ehcache>
mybatis中mapper配置