詳解Mybatis的緩存
mybatis是一個(gè)查詢(xún)數(shù)據(jù)庫(kù)的封裝框架,主要是封裝提供靈活的增刪改sql,開(kāi)發(fā)中,service層能夠通過(guò)mybatis組件查詢(xún)和修改數(shù)據(jù)庫(kù)中表的數(shù)據(jù);作為查詢(xún)工具,mybatis有使用緩存,這里講一下mybatis的緩存相關(guān)源碼。
緩存
在計(jì)算機(jī)里面,任何信息都有源頭,緩存一般指源頭信息讀取后,放在內(nèi)存或者其他讀取較快的地方,下次讀取相同信息不去源頭查詢(xún)而是直接從內(nèi)存(或者能快速存取的硬件)讀取。這樣可以減少硬件使用,提高讀取速度。
mybatis也是這樣,查詢(xún)數(shù)據(jù)庫(kù)的數(shù)據(jù)之后,mybatis可以把查詢(xún)結(jié)果緩存到內(nèi)存,下次查詢(xún)?nèi)绻樵?xún)語(yǔ)句相同,并且查詢(xún)相關(guān)的表的數(shù)據(jù)沒(méi)被修改過(guò),就可以直接返回緩存中的結(jié)果,而不用去查詢(xún)數(shù)據(jù)庫(kù)的語(yǔ)句,有效節(jié)省了時(shí)間。
簡(jiǎn)單看一下mybatis一級(jí)緩存和二級(jí)緩存相關(guān)源碼,學(xué)習(xí)使用
一級(jí)緩存通過(guò)查看源碼可知,一級(jí)緩存是綁定sqSsession中的,所以每次查詢(xún)sqlSession不同就失效,相同的sqlSession可以使用一級(jí)緩存。
mybatis默認(rèn)sqlsession:org.apache.ibatis.session.defaults.DefaultSqlSession
構(gòu)造方法中傳入executor(查詢(xún)執(zhí)行對(duì)象)
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; }
executor中攜帶一級(jí)緩存成員:
protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<>(); this.localCache = new PerpetualCache('LocalCache'); //默認(rèn)一級(jí)緩存 this.localOutputParameterCache = new PerpetualCache('LocalOutputParameterCache'); this.closed = false; this.configuration = configuration; this.wrapper = this; }查詢(xún)使用一級(jí)緩存邏輯
org.apache.ibatis.executor.BaseExecutor.query()
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()); List<E> list; try { queryStack++; //localCache 一級(jí)緩存 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; //先從一級(jí)緩存中獲取,key是通過(guò)sql語(yǔ)句生成 if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 如果緩存中沒(méi)有 才從數(shù)據(jù)庫(kù)查詢(xún) list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } return list; } //從數(shù)據(jù)庫(kù)讀取數(shù)據(jù) private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key);//將一級(jí)緩存清除 } localCache.putObject(key, list);//返回查詢(xún)結(jié)果之前,先放入一級(jí)緩存 刷新 if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }二級(jí)緩存
二級(jí)緩存mapper中的,默認(rèn)是開(kāi)啟的,但需要在映射文件mapper.xml中添加<cache/>標(biāo)簽
<mapper namespace='userMapper'><cache/><!-- 添加cache標(biāo)簽表示此mapper使用二級(jí)緩存 --></mapper>
配置false可以關(guān)閉二級(jí)緩存
二級(jí)緩存的解析org.apache.ibatis.builder.xml.XMLMapperBuilder
private void configurationElement(XNode context) { try { //... cacheElement(context.evalNode('cache')); //解析cache標(biāo)簽 } catch (Exception e) { throw new BuilderException('Error parsing Mapper XML. The XML location is ’' + resource + '’. Cause: ' + e, e); } } private void cacheElement(XNode context) { if (context != null) { // if hava cache tag 如果有cache標(biāo)簽才執(zhí)行下面的邏輯 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); boolean blocking = context.getBooleanAttribute('blocking', false); Properties props = context.getChildrenAsProperties(); builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);//建立二級(jí)緩存 } }
org.apache.ibatis.builder.MapperBuilderAssistant.useNewCache():
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { Cache cache = new CacheBuilder(currentNamespace) .implementation(valueOrDefault(typeClass, PerpetualCache.class)) .addDecorator(valueOrDefault(evictionClass, LruCache.class)) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); configuration.addCache(cache);//二級(jí)緩存賦值,如果cache標(biāo)簽為空,不會(huì)執(zhí)行此方法,currentCache為空 currentCache = cache; return cache; }
在映射文件mapper中如果沒(méi)有cache標(biāo)簽,不會(huì)執(zhí)行上面的useNewCache方法,cache為null,就不會(huì)使用二級(jí)緩存(相當(dāng)于失效)。
查詢(xún)使用二級(jí)緩存邏輯org.apache.ibatis.executor.CachingExecutor :
@Override 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) {//如果二級(jí)緩存對(duì)象不為空 嘗試在二級(jí)緩存中獲取(沒(méi)有cache標(biāo)簽此對(duì)象就是空) flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings('unchecked') List<E> list = (List<E>) tcm.getObject(cache, key); //從二級(jí)緩存中獲取數(shù)據(jù) if (list == null) { list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //如果為空,使用delegate查詢(xún)(BaseExecutor) tcm.putObject(cache, key, list); // 查詢(xún)結(jié)果保存到二級(jí)緩存 } return list; } } return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
二級(jí)緩存和一級(jí)緩存不用想,數(shù)據(jù)庫(kù)的數(shù)據(jù)被修改是要清空緩存的,不然數(shù)據(jù)有誤,至于怎么清空,是另一套邏輯了,mapper中的cache標(biāo)簽可以配置一些參數(shù),比如緩存定期清空。
一級(jí)二級(jí)緩存先后順序mybatis默認(rèn)是先查詢(xún)二級(jí)緩存,沒(méi)有,再查看一級(jí)緩存,都為空,最后查詢(xún)數(shù)據(jù)庫(kù)
以上就是詳解Mybatis的緩存的詳細(xì)內(nèi)容,更多關(guān)于Mybatis的緩存的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. MySQL基礎(chǔ)教程9 —— 函數(shù)之日期和時(shí)間函數(shù)2. 用SQL SERVER記錄站點(diǎn)日志3. mssql鎖基礎(chǔ)教程4. 數(shù)據(jù)庫(kù)人員手冊(cè)之ORACLE應(yīng)用源碼5. MySQL 千萬(wàn)級(jí)數(shù)據(jù)量如何快速分頁(yè)6. Mybatis查詢(xún)方法如何實(shí)現(xiàn)沒(méi)有返回值7. DB2 XML 全文搜索之為文本搜索做準(zhǔn)備8. 快速解決mysql導(dǎo)出scv文件亂碼、躥行的問(wèn)題9. Microsoft Office Access修改代碼字體大小的方法10. centos 7安裝mysql5.5和安裝 mariadb使用的命令
