mybatis兩級快取原理剖析

2021-08-21 11:51:11 字數 3325 閱讀 8156

對於mybatis的快取認識一直有乙個誤區,所以今天寫一篇文章幫自己訂正一下。mybatis的快取分一級快取與二級快取。下面分別對這兩種快取進行詳細解說。

首先我們需要大致的了解一下mybatis的呼叫鏈,然後才能更好的理解mybatis的快取。

主要的api羅列如下:

public inte***ce sqlsessionfactory 

public class defaultsqlsessionfactory implements sqlsessionfactory

private sqlsession opensessionfromdatasource(executortype exectype, transactionisolationlevel level, boolean autocommit) catch (exception e) finally

}}configuration中的

public executor newexecutor(transaction transaction, executortype executortype) else if (executortype.reuse == executortype) else

if (cacheenabled)

executor = (executor) interceptorchain.pluginall(executor); //mybatis的外掛程式機制

return executor;

}

上面的**大致描述了,我們為了獲取乙個sqlsession例項的過程。下面的方法為sqlsession的實現類defaultsqlsession中的乙個查詢方法.

@override

public listselectlist(string statement, object parameter, rowbounds rowbounds) catch (exception e) finally

}

從該方法我們可知sqlsession的方法實現全部委託給了executor例項。executor介面的類圖:

上面的executor.query如何執行呢?public abstract class baseexecutor 中的方法給了我們答案.

@override

boundsql boundsql = ms.getboundsql(parameter);

cachekey key = createcachekey(ms, parameter, rowbounds, boundsql);

return query(ms, parameter, rowbounds, resulthandler, key, boundsql);

} @suppresswarnings("unchecked")

@override

errorcontext.instance().resource(ms.getresource()).activity("executing a query").object(ms.getid());

if (closed)

if (querystack == 0 && ms.isflushcacherequired())

listlist;

try else

} finally

if (querystack == 0)

// issue #601

deferredloads.clear();

if (configuration.getlocalcachescope() == localcachescope.statement)

}return list;

}

請注意localcache是什麼呢?在baseexecutor的構造器有這麼一句**: this.localcache = new perpetualcache(「localcache」); 即locacache為快取,即mybatis的一級快取。

localcache生命週期是與sqlsession的生命週期是一樣;不同的sqlsession會生成不同的localcache.這就是mybatis的一級快取,它是與sqlsession息息相關,只能單個sqlsession例項獨享。並且預設是開啟的,沒有開關可以關閉它。但是它的使用非常有侷限。所以mybatis才需要在二級快取,即突破sqlsession範圍的快取。mybatis的二級快取與我們通常認知的快取沒有區別。

mybatis的二級快取即通過cachingexecutor來實現。

cachingexecutor 中的query方法**如下:

@override

throws sqlexception

return list;}}

return delegate.query(ms, parameterobject, rowbounds, resulthandler, key, boundsql);

}

即當cache不為null時,則從tcm中獲取,如果獲取不到則再從delegate中獲取。

現在關鍵是tcm.getobject(cache, key);

private final transactionalcachemanager tcm = new transactionalcachemanager();

transactionalcachemanager的部分源**

public class transactionalcachemanager 

private transactionalcache gettransactionalcache(cache cache)

}

transactionalcache 部分原始碼

public transactionalcache(cache delegate) 

@override

public object getobject(object key)

// issue #146

if (clearoncommit) else

}

峰迴路轉

cache cache = ms.getcache(); //這句是重點
這樣就可以最簡單的方式使用mybatis的二級快取了。至於如何擴充套件mybatis的二級快取,不在本文之列。

mybatis的兩級快取

mybatis的快取有兩種,分為一級快取和二級快取,它們的作用域不同。一級快取我個人也叫session快取,它預設是開啟的,不可配置的。為啥叫session快取,是因為它的作用域是session範圍內的,也就是說同乙個session的情況才能使用到一級快取,目前我遇到的情況就是在乙個事務內查詢兩次資...

Mybatis的二級快取剖析

研究mybatis的二級快取需要去扒拉下人家的源 研究mybatis提供的官方jar包 研究方向萬變不離其宗,就算不去看人家的源 我們猜一猜也能猜到個大概,大概是用map快取,然後用整串的sql 引數作為key,然後查詢結果作為value,至於是不是我們可以後面再瞅瞅。我們主要看兩塊兒,一塊兒是ca...

3 1 9 兩級頁表

單級頁表的幾個問題 1 因為頁表的特性,需要連續存放,當程序需要很多個頁面,就需要很大的頁表,就需要很大一塊連續的區域去存放頁表 2 根據區域性性原理,沒必要讓頁表常駐記憶體 因為頁表太大,需要連續一大片記憶體的解決方法是 重新建立起對一級頁表的頁表,頁目錄表 將邏輯位址程序拆分成一級頁號和二級頁號...