一 配置
private void cacheElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
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();
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props);
}
}
二 初始化
2.1 cache创建CacheBuilder.build()
-
setDefaultImplementations();
初始化cache的实现类,
private void setDefaultImplementations() {
if (implementation == null) {
// implementation表示存储类型,默认PerpetualCache是内存map存储。
implementation = PerpetualCache.class;
if (decorators.size() == 0) {
//decorators表示过期策略,默认LruCache是最近最少使用过期策略
decorators.add(LruCache.class);
}
}
}
-
Cache cache = newBaseCacheInstance(implementation, id);
初始化缓存类
-
setCacheProperties(cache);
配置值按属性注入到缓存对象中
2.1.1 PerpetualCache类型处理
- 按配置过期策略decorators创建代理类,注入配置
-
clearInterval
配置则创建ScheduledCache,周期清理缓存
-
readWrite
配置则创建SerializedCache,读写缓存时序列化处理
- 创建LoggingCache代理纪录命中率
- 创建SynchronizedCache代理,加锁控制并发
if (PerpetualCache.class.equals(cache.getClass())) { // issue #352, do not apply decorators to custom caches
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
cache = setStandardDecorators(cache);
}
private Cache setStandardDecorators(Cache cache) {
try {
MetaObject metaCache = SystemMetaObject.forObject(cache);
if (size != null && metaCache.hasSetter("size")) {
metaCache.setValue("size", size);
}
if (clearInterval != null) {
cache = new ScheduledCache(cache);
((ScheduledCache) cache).setClearInterval(clearInterval);
}
if (readWrite) {
cache = new SerializedCache(cache);
}
cache = new LoggingCache(cache);
cache = new SynchronizedCache(cache);
return cache;
} catch (Exception e) {
throw new CacheException("Error building standard cache decorators. Cause: " + e, e);
}
}
2.1.2 其他类型处理
- 非LoggingCache类型缓存,则创建LoggingCache代理纪录命中率
2.2 cache缓存
-
configuration.addCache(cache);
配置中保存cache
-
mappedStatement.cache
也保存cache
2.3 缓存代理
2.3.1 LruCache
- 使用LinkedHashMap实现,size为缓存最大数量,且为最近使用的缓存。
- LinkedHashMap是在hashmap存储时,额外使用链表存储对象,每次操作的对象都提取到链表头,表示最近使用
- 重写removeEldestEntry方法,只保存size数量的缓存数据。
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L;
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
2.3.2 ScheduledCache
- 所有缓存操作前,先检查距离上次处理是否达到周期时间,默认1h
-
System.currentTimeMillis() - lastClear > clearInterval
达到周期时间,则清除所有缓存。
2.3.3 ScheduledCache
- 序列化代理,读写缓存前对对象进行序列化或反序列化处理。非内存缓存时使用。
2.3.4 LoggingCache
- 获取缓存时,纪录请求次数和成功纪录
-
(double) hits / (double) requests
计算缓存命中率
2.3.5 SynchronizedCache
- 所有缓存操作方法使用
synchronized
进行并发控制。
三 使用
- 配置使用二级缓存
cacheEnabled
,则创建执行器代理CachingExecutor
- 查询操作时,
Cache cache = ms.getCache();
获取初始化的缓存
- 若sql查询配置了flushCacheRequired,则不使用缓存,sql查询前清除缓存
- 存在缓存则使用,不存在则查询后新增缓存。使用TransactionalCacheManager管理缓存
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
3.1 TransactionalCacheManager
-
Map<Cache, TransactionalCache> transactionalCaches
存储缓存
3.2 TransactionalCache
- 事务内的缓存数据管理,事务commit前先缓存在TransactionalCache中,提交时再统一向目标cache进行缓存或删除操作。
public void putObject(Object key, Object object) {
entriesToRemoveOnCommit.remove(key);
entriesToAddOnCommit.put(key, new AddEntry(delegate, key, object));
}
public Object removeObject(Object key) {
entriesToAddOnCommit.remove(key);
entriesToRemoveOnCommit.put(key, new RemoveEntry(delegate, key));
return delegate.getObject(key);
}
-
entriesToAddOnCommit
事务提交时要保存的缓存
-
entriesToRemoveOnCommit
事务提交时要删除的缓存
- 事务提交时,遍历entriesToAddOnCommit和entriesToRemoveOnCommit,对目标缓存进行操作。然后
reset()
清空
public void commit() {
if (clearOnCommit) {
delegate.clear();
} else {
for (RemoveEntry entry : entriesToRemoveOnCommit.values()) {
entry.commit();
}
}
for (AddEntry entry : entriesToAddOnCommit.values()) {
entry.commit();
}
reset();
}
private void reset() {
clearOnCommit = false;
entriesToRemoveOnCommit.clear();
entriesToAddOnCommit.clear();
}
网友评论