通常的ORM(Object Relational Mapping)框架都會提供緩存功能以減小訪問數據庫的次數,減輕數據庫壓力,提升查詢效率。MyBatis中有一級和默認實現的二級緩存,並且MyBatis也預留了集成第三方緩存的接口(二級緩存接口的自定義實現)。sql
先經過一段源碼來看看mybatis的查詢的執行流程。數據庫
緩存
2> 執行query方法mybatis
1 @Override 2 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) 3 throws SQLException { 4 //獲取緩存對象 5 Cache cache = ms.getCache(); 6 if (cache != null) {//存在緩存 7 //嘗試刷新緩存,確保緩存是最新 8 flushCacheIfRequired(ms); 9 //若是緩存啓用而且該查詢沒有用到ResultHandler 10 if (ms.isUseCache() && resultHandler == null) { 11 //參數檢查 12 ensureNoOutParams(ms, boundSql); 13 @SuppressWarnings("unchecked") 14 //從緩存中讀取 15 List<E> list = (List<E>) tcm.getObject(cache, key); 16 if (list == null) {//未命中,調用默認執行器執行query 17 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 18 //查詢結果放入緩存 19 tcm.putObject(cache, key, list); // issue #578 and #116 20 } 21 return list; 22 } 23 } 24 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); 25 }
經過上面一段代碼,能夠發現如下兩個問題:app
首先,你們大概能夠猜想出mybatis中一級緩存和二級緩存的優先級順序了吧?😂沒錯,在開啓二級緩存的狀況下會先從二級緩存中讀取——>二級緩存未命中的話會調用默認執行器的query方法——>默認執行器再讀取本身的一級緩存——>未命中則訪問數據庫——>查詢結果放入緩存。框架
二級緩存是保存在MappedStatement中的,MappedStatement是用來存放咱們的定義DAO層的mapper的信息。一個mapper接口對應一個MappedStatement,那麼二級緩存的做用域就是同一mapper下有效。ide
mybatis 的一級緩存是sqlSession級別的,緩存做用域是在一次數據庫會話中有效。一級緩存是持久化緩存(本地緩存)而且是默認開啓的,不須要手動開啓。ui
爲何說一級緩存是Session級別的而且是本地緩存呢?mybatis中每個sqlSession都會對應一個繼承自BaseExecutor的Executor(默認是SimipleExecutor)。而BaseExecutor中存在兩個PerpetualCache類型的實現Cache接口的對象,見名知意,它就是一個持久化的緩存對象,具體的持久化實現很少贅述(沒看😢)。spa
爲了不髒讀,sqlSession執行了DML操做(insert、update、delete),並commit了以後,mybatis會清空當前sqlSession緩存中的全部緩存數據。code
從開頭的源碼解讀能夠看出,二級緩存的做用域是同一mpper接口,全部的sqlSession查詢結果都會走MapperStatement中的Cache。mybatis中的二級緩存默認是關閉的須要手動開啓。
開啓mybatis二級緩存的方法:
在mybatis配置文件中添加下面的設置
<settings> <setting name="cacheEnabled" value="true"/> </settings>
在須要開啓二級緩存的mapper.xml文件中添加下面的配置
<!-- 當前mapper下全部語句開啓二級緩存 --> <!-- 也能夠在對應的mapper接口上添加@CacheNamespace註解 --> <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
具體的執行流程能夠看開頭的源碼解析,不過多贅述