mybatis缓存 - 969251639/study GitHub Wiki
mybatis的缓存分为两种,分别是一级缓存和二级缓存,二级缓存需要依赖第三方缓存,一级缓存则是自带
1. 二级缓存
在mybatis的配置中可以指定开启
<configuration>
...
<settings>
<setting name="cacheEnabled" value="true" />
...
</settings>
...
</configuration>
即是不指定,默认也是开启的
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
mybatis二级缓存是通过一个特殊包装的执行器来实现的
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);//二级缓存执行器
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
CachingExecutor内部的delegate属性保存了基础执行器的引用
private final Executor delegate;
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
在执行查询操作的时候会先去查询缓存,查询不到就调用执行器查询
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();//从mapper中获取缓存对象
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, 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 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
需要注意的是,这个缓存是全局的,也就是所有session共享
1. 一级缓存
一级缓存和二级缓存不一样,它是session级别,每次查询sql时都会判断一下缓存是否存在(如果开启的话)
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//计算缓存键
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {//是否关闭一级缓存
clearLocalCache();//关闭一级缓存就直接清空缓存
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;//从缓存获取
if (list != null) {//缓存命中
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {//查询数据库
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
...
return list;
}
另外所有的更新操作都会使缓存失效
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();//缓存失效
return doUpdate(ms, parameter);
}