日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mybatis二级缓存原理

發(fā)布時(shí)間:2025/3/21 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis二级缓存原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

記錄是一種精神,是加深理解最好的方式之一。

最近看了下Mybatis的源碼,分析了二級緩存的實(shí)現(xiàn)方式,在這里把他記下來。雖然這不復(fù)雜,對這方面的博客也有很多,寫的也很好。但我堅(jiān)信看懂了是其一,能夠教別人或者描述清楚記下來才能真正的掌握。
曹金桂 cao_jingui@163.com (如有欠缺還請指教)
時(shí)間:2016年10月11日16:00

這篇文章能夠幫你

  • 學(xué)會(huì)對Mybatis配置二級緩存
  • 學(xué)會(huì)Mybatis二級緩存的實(shí)現(xiàn)方式
  • 學(xué)會(huì)整合外部緩存框架(如:Ehcache)
  • 學(xué)會(huì)自定義二級緩存

1. Mybatis內(nèi)部二級緩存的配置

要使用Mybatis的二級緩存,需要對Mybatis進(jìn)行配置,配置分三步

  • Mybatis全局配置中啟用二級緩存配置
<setting name="cacheEnabled" value="true"/>
  • 在對應(yīng)的Mapper.xml中配置cache節(jié)點(diǎn)
<mapper namespace="userMapper"><cache /><result ... /><select ... /> </mapper>
  • 在對應(yīng)的select查詢節(jié)點(diǎn)中添加useCache=true
<select id="findUserById" parameterType="int" resultMap="user" useCache="true">select * from users where id=#{id}; </select>
  • 高級配置

a. 為每一個(gè)Mapper分配一個(gè)Cache緩存對象(使用<cache>節(jié)點(diǎn)配置)
b. 多個(gè)Mapper共用一個(gè)Cache緩存對象(使用<cache-ref>節(jié)點(diǎn)配置)

只要簡單的三步配置即可開啟Mybatis的二級緩存了。在使用mybatis查詢時(shí)候("userMapper.findUserById"),不同會(huì)話(Sqlsession)在查詢時(shí)候,只會(huì)查詢數(shù)據(jù)庫一次,第二次會(huì)從二級緩存中讀取。

@Before public void before() {String mybatisConfigFile = "MybatisConfig/Mybatis-conf.xml";InputStream stream = TestMybatis.class.getClassLoader().getResourceAsStream(mybatisConfigFile);sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //構(gòu)建sqlSession的工廠 } @Test public void test() {SqlSession sqlSession = sqlSessionFactory.openSession();User i = sqlSession.selectOne("userMapper.findUserById", 1);System.out.println(i);sqlSession.close();sqlSession = sqlSessionFactory.openSession();User x = sqlSession.selectOne("userMapper.findUserById", 1); // 讀取二級緩存數(shù)據(jù)System.out.println(x);sqlSession.close(); }

2. Mybatis內(nèi)部二級緩存的設(shè)計(jì)及工作模式

?

首先我們要知道,mybatis的二級緩存是通過CacheExecutor實(shí)現(xiàn)的。CacheExecutor其實(shí)是Executor的代理對象。所有的查詢操作,在CacheExecutor中都會(huì)先匹配緩存中是否存在,不存在則查詢數(shù)據(jù)庫。

3. 內(nèi)部二級緩存的實(shí)現(xiàn)詳解

竟然知道Mybatis二級緩存是通過CacheExecotur實(shí)現(xiàn)的,那看下Mybatis中創(chuàng)建Executor的過程

// 創(chuàng)建執(zhí)行器(Configuration.newExecutor) public Executor newExecutor(Transaction transaction, ExecutorType executorType) {//確保ExecutorType不為空(defaultExecutorType有可能為空)executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : 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; }

重點(diǎn)在cacheEnabled這個(gè)參數(shù)。如果你看了我的文章[Mybatis配置文件解析過程詳解],就應(yīng)該知道了怎么設(shè)置cacheEnabled。對,就是此文章第一點(diǎn)說的開啟Mybatis的全局配置項(xiàng)。我們繼續(xù)看下CachingExecutor具體怎么實(shí)現(xiàn)的。

public class CachingExecutor implements Executor {private Executor delegate;public CachingExecutor(Executor delegate) {this.delegate = delegate;delegate.setExecutorWrapper(this);}public int update(MappedStatement ms, Object parameterObject) throws SQLException {flushCacheIfRequired(ms); //是否需要更緩存return delegate.update(ms, parameterObject); //更新數(shù)據(jù)}...... }

很清晰,靜態(tài)代理模式。在CachingExecutor的所有操作都是通過調(diào)用內(nèi)部的delegate對象執(zhí)行的。緩存只應(yīng)用于查詢,我們看下CachingExecutor的query方法。

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameterObject);//創(chuàng)建緩存值CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);//獲取記錄return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }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) {flushCacheIfRequired(ms);if (ms.isUseCache() && resultHandler == null) {// ensureNoOutParamsif (ms.getStatementType() == StatementType.CALLABLE) {for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {if (parameterMapping.getMode() != ParameterMode.IN) {throw new ExecutorException("Caching stored procedures with OUT params is not supported. Please configure useCache=false in " + ms.getId() + " statement.");}}}List<E> list = (List<E>) tcm.getObject(cache, key); //從緩存中獲取數(shù)據(jù)if (list == null) {list = delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);tcm.putObject(cache, key, list); // 結(jié)果保存到緩存中}return list;}}return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }

如果MappedStatement中對應(yīng)的Cache存在,并且對于的查詢開啟了二級緩存(useCache="true"),那么在CachingExecutor中會(huì)先從緩存中根據(jù)CacheKey獲取數(shù)據(jù),如果緩存中不存在則從數(shù)據(jù)庫獲取。這里的代碼很簡單,很容易理解。
說到緩存,有效期和緩存策略不得不提。在Mybatis中二級緩存也實(shí)現(xiàn)了有效期的控制和緩存策略。Mybatis中是使用裝飾模式實(shí)現(xiàn)的,具體可以看下mybatis的cache包

?

?

具體于配置如下:

<cache eviction="FIFO|LRU|SOFT|WEAK" flushInterval="300" size="100" />

對應(yīng)具體實(shí)現(xiàn)源碼可以參考CacheBuilder類的源碼。

public Cache build() {if (implementation == null) { //緩存實(shí)現(xiàn)類implementation = PerpetualCache.class;if (decorators.size() == 0) {decorators.add(LruCache.class);}}Cache cache = newBaseCacheInstance(implementation, id);setCacheProperties(cache);if (PerpetualCache.class.equals(cache.getClass())) {for (Class<? extends Cache> decorator : decorators) {cache = newCacheDecoratorInstance(decorator, cache);setCacheProperties(cache);}// 采用默認(rèn)緩存包裝類cache = setStandardDecorators(cache);} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {cache = new LoggingCache(cache);}return cache; }

4. 一級緩存和二級緩存的使用順序

如果你的MyBatis使用了二級緩存,并且你的Mapper和select語句也配置使用了二級緩存,那么在執(zhí)行select查詢的時(shí)候,MyBatis會(huì)先從二級緩存中取輸入,其次才是一級緩存,即MyBatis查詢數(shù)據(jù)的順序是:

二級緩存 ———> 一級緩存——> 數(shù)據(jù)庫

5. mybatis二級緩存和分頁插件同時(shí)使用產(chǎn)生的問題

問題:分頁插件開啟二級緩存后,分頁查詢時(shí)無論查詢哪一頁都返回第一頁的數(shù)據(jù)

在之前講解Mybatis的執(zhí)行流程的時(shí)候提到,在開啟cache的前提下,Mybatis的executor會(huì)先從緩存里讀取數(shù)據(jù),讀取不到才去數(shù)據(jù)庫查詢。問題就出在這里,sql自動(dòng)生成插件和分頁插件執(zhí)行的時(shí)機(jī)是在statementhandler里,而statementhandler是在executor之后執(zhí)行的,無論sql自動(dòng)生成插件和分頁插件都是通過改寫sql來實(shí)現(xiàn)的,executor在生成讀取cache的key(key由sql以及對應(yīng)的參數(shù)值構(gòu)成)時(shí)使用都是原始的sql,這樣當(dāng)然就出問題了。
找到問題的原因后,解決起來就方便了。只要通過攔截器改寫executor里生成key的方法,在生成可以時(shí)使用自動(dòng)生成的sql(對應(yīng)sql自動(dòng)生成插件)或加入分頁信息(對應(yīng)分頁插件)就可以了。
參考:http://blog.csdn.net/hupanfeng/article/details/16950161

6. mybatis整合第三方緩存框架

?

我們以ehcache為例。對于ehcache我只會(huì)簡單的使用。這里我只是介紹Mybatis怎么使用ehcache,不對ehcache配置作說明。我們知道,在配置二級緩存時(shí)候,我們可以指定對應(yīng)的實(shí)現(xiàn)類。這里需要mybatis-ehcache-1.0.3.jar這個(gè)jar包。在Mapper中我們只要配置如下即可。

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

當(dāng)然,項(xiàng)目中ehcache的配置還是需要的。

小結(jié)

對于Mybatis整合第三方的緩存,實(shí)現(xiàn)騎士很簡單,只要在配置的地方制定實(shí)現(xiàn)類即可。
Mybatis默認(rèn)二級緩存的實(shí)現(xiàn)在集群或者分布式部署下是有問題的,Mybatis默認(rèn)緩存只在當(dāng)節(jié)點(diǎn)內(nèi)有效,并且對緩存的失效操作無法同步的其他節(jié)點(diǎn)。需要整合第三方分布式緩存實(shí)現(xiàn),如ehcache或者自定義實(shí)現(xiàn)。



作者:曹金桂
鏈接:https://www.jianshu.com/p/5ff874fa696f
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。

總結(jié)

以上是生活随笔為你收集整理的Mybatis二级缓存原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。