對於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 根據區域性性原理,沒必要讓頁表常駐記憶體 因為頁表太大,需要連續一大片記憶體的解決方法是 重新建立起對一級頁表的頁表,頁目錄表 將邏輯位址程序拆分成一級頁號和二級頁號...