緩存
當(dāng)我們發(fā)起一次數(shù)據(jù)庫查詢時(shí)森逮,如果啟用了二級緩存的話艾岂,MyBatis 首先會(huì)先從二級緩存中檢索查詢結(jié)果合陵,如果緩存不命中則會(huì)繼續(xù)檢索一級緩存沼填,只有在這兩層緩存都不命中的情況下才會(huì)查詢數(shù)據(jù)庫桅咆,最后會(huì)以數(shù)據(jù)庫返回的結(jié)果更新一級緩存和二級緩存。
一級緩存是基于 sqlSession 的坞笙,而 二級緩存是基于 mapper文件的namespace
也就是說多個(gè)sqlSession可以共享一個(gè)mapper中的二級緩存區(qū)域岩饼,并且如果兩個(gè)mapper的namespace相同荚虚,即使是兩個(gè)mapper,那么這兩個(gè)mapper中執(zhí)行sql查詢到的數(shù)據(jù)也將存在相同的二級緩存區(qū)域中
先看看創(chuàng)建Executor的過程:
// 創(chuàng)建執(zhí)行器(Configuration.newExecutor)
public Executor newExecutor(Transaction transaction, ExecutorType 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) { //重點(diǎn)在這里籍茧,如果啟用全局代理對象版述,返回Executor的Cache包裝類對象 executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor;}
一級緩存
BaseExecutor 是一個(gè)抽象類,實(shí)現(xiàn)了 Executor 接口中聲明的所有方法硕糊。BaseExecutor 抽象類引入了一級緩存支持院水,在相應(yīng)方法實(shí)現(xiàn)中增加了對一級緩存的操作,因此該類的所有派生類都具備一級緩存的特性简十。一級緩存比較簡單檬某,具體實(shí)現(xiàn)是PerpetualCache
二級緩存
由上面創(chuàng)建執(zhí)行器可以看出,二級緩存是需要單獨(dú)配置的螟蝙。
需要以下兩步:全局配置:mapper配置: 多個(gè)Mapper共用一個(gè)Cache緩存對象(使用節(jié)點(diǎn)配置)詳細(xì)實(shí)現(xiàn):CachingExecutor其實(shí)是個(gè)代理模式恢恼,所有操作都是通過deleget來完成的。private Executor delegate;只有查詢緩存是自己實(shí)現(xiàn)的胰默。緩存策略:先看緩存的構(gòu)建:
CacheBuilder
public Cache build() {
setDefaultImplementations();
Cache cache = newBaseCacheInstance(this.implementation, this.id);
..
return cache;
}
setDefaultImplementations:
this.implementation = PerpetualCache.class;
if (this.decorators.isEmpty())
? ? this.decorators.add(LruCache.class);
}
可以看出二級緩存的默認(rèn)實(shí)現(xiàn)也是PerpetualCache场斑,另外緩存策略是通過裝飾器模式來實(shí)現(xiàn)的,默認(rèn)的緩存策略是LRU
完整的一級緩存牵署、二級緩存的工作漏隐,其中一級緩存的實(shí)現(xiàn)真正是通過BaseExecutor實(shí)現(xiàn)。