在上一篇文章中我们主要对mybatis拦截器进行了研究。通过分析我们主要学习到mybatis这种插件的设计理念的优点。除此之外还有jdk动态代理与责任链模式的完美结合都是我们在项目实践中榜样。当然今天我们主要不是复习,而是学习mybatis的缓存。我们在第二篇文章中说mybatis有缓存,但是我们并没有进行详细的说明,在此我们详细的研究一下。
我们在业务中经常需要注入mybatis的mapper进行数据库的操作,但是因为业务不同我们经常要将相同的mapper注入的不同的业务层中去,但是我们说过我们注入的mapper其实本质是一个sqlsession的实体。基于这一点我们知道mybatis缓存也就是基于会话的,如果是这样,那么如果不同的会话对数据库的修改是不是就会产生脏数据的问题。除此之外如果我们使用的是分布式服务,如果我们使用mybatis缓存,不同的机器那么缓存就更乱了。这里我们所说的其实是mybatis的一级缓存。在此我们对照源码看一下一级缓存的相关过程。
public Listquery(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 list;
try {
queryStack++;
//从一级缓存中查询
list = resultHandler == null ? (List) localCache.getObject(key) : null;
if (list != null) {
//处理存储过程
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//直接查看
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
//如果缓存的范围是statement,则查询结束之后就清空缓存
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
我们看到这块的逻辑还是先走缓存,如果缓存不存在就直接查库,然后再回写到缓存中。这块我们看一下这个缓存是怎么初始化的。