真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

總結(jié)MyBatis緩存結(jié)構(gòu)

這篇文章主要介紹“總結(jié)MyBatis緩存結(jié)構(gòu)”,在日常操作中,相信很多人在總結(jié)MyBatis緩存結(jié)構(gòu)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對(duì)大家解答”總結(jié)MyBatis緩存結(jié)構(gòu)”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

“專業(yè)、務(wù)實(shí)、高效、創(chuàng)新、把客戶的事當(dāng)成自己的事”是我們每一個(gè)人一直以來堅(jiān)持追求的企業(yè)文化。 創(chuàng)新互聯(lián)是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、軟件開發(fā)、設(shè)計(jì)服務(wù)業(yè)務(wù)。我們始終堅(jiān)持以客戶需求為導(dǎo)向,結(jié)合用戶體驗(yàn)與視覺傳達(dá),提供有針對(duì)性的項(xiàng)目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場(chǎng),引領(lǐng)市場(chǎng)!

二級(jí)緩存

主要內(nèi)容:

總結(jié)MyBatis緩存結(jié)構(gòu)

二級(jí)緩存構(gòu)建在一級(jí)緩存之上,在收到查詢請(qǐng)求時(shí),MyBatis 首先會(huì)查詢二級(jí)緩存。若二級(jí)緩存未命中,再去查詢一級(jí)緩存。與一級(jí)緩存不同,二級(jí)緩存和具體的命名空間綁定,一級(jí)緩存則是和 SqlSession 綁定。

在按照 MyBatis 規(guī)范使用 SqlSession 的情況下,一級(jí)緩存不存在并發(fā)問題。二級(jí)緩存則不然,二級(jí)緩存可在多個(gè)命名空間間共享。這種情況下,會(huì)存在并發(fā)問題,因此需要針對(duì)性去處理。除了并發(fā)問題,二級(jí)緩存還存在事務(wù)問題。

二級(jí)緩存如何開啟?

配置項(xiàng)


  
    

cacheEnabled=true表示二級(jí)緩存可用,但是要開啟話,需要在Mapper.xml內(nèi)配置。


或者 簡單方式

對(duì)配置項(xiàng)屬性說明:

  • flushInterval="60000",間隔60秒清空緩存,這個(gè)間隔60秒,是被動(dòng)觸發(fā)的,而不是定時(shí)器輪詢的。

  • size=512,表示隊(duì)列最大512個(gè)長度,大于則移除隊(duì)列最前面的元素,這里的長度指的是CacheKey的個(gè)數(shù),默認(rèn)為1024。

  • readOnly="true",表示任何獲取對(duì)象的操作,都將返回同一實(shí)例對(duì)象。如果readOnly="false",則每次返回該對(duì)象的拷貝對(duì)象,簡單說就是序列化復(fù)制一份返回。

  • eviction:緩存會(huì)使用默認(rèn)的Least Recently Used(LRU,最近最少使用的)算法來收回。FIFO:First In First Out先進(jìn)先出隊(duì)列。

在Configuration類的newExecutor方法中是否開啟二級(jí)緩存

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    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);
    }
      //是否開啟二級(jí)緩存
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

二級(jí)緩存通過CachingExecutor來實(shí)現(xiàn)的,原理是緩存里存在,就返回,不存在就調(diào)用Executor ,如果一級(jí)緩存未關(guān)閉,則先查一級(jí)緩存,不存在,再到數(shù)據(jù)庫中查詢。

下面使用一張圖來表示:

總結(jié)MyBatis緩存結(jié)構(gòu)

下面是源碼:

@Override
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    // 獲得 BoundSql 對(duì)象
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    // 創(chuàng)建 CacheKey 對(duì)象
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    // 查詢
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
            throws SQLException {
    // 調(diào)用 MappedStatement#getCache() 方法,獲得 Cache 對(duì)象,
    //即當(dāng)前 MappedStatement 對(duì)象的二級(jí)緩存。
    Cache cache = ms.getCache();
    if (cache != null) { // <2> 
        // 如果需要清空緩存,則進(jìn)行清空
        flushCacheIfRequired(ms);
        //當(dāng) MappedStatement#isUseCache() 方法,返回 true 時(shí),才使用二級(jí)緩存。默認(rèn)開啟。   
        //可通過@Options(useCache = false) 或  方法,關(guān)閉。
        if (ms.isUseCache() && resultHandler == null) { // <2.2>
            // 暫時(shí)忽略,存儲(chǔ)過程相關(guān)
            ensureNoOutParams(ms, boundSql);
            @SuppressWarnings("unchecked")
            //從二級(jí)緩存中,獲取結(jié)果
            List list = (List) tcm.getObject(cache, key);
            if (list == null) {
                // 如果不存在,則從數(shù)據(jù)庫中查詢
                list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                // 緩存結(jié)果到二級(jí)緩存中
                tcm.putObject(cache, key, list); // issue #578 and #116
            }
            // 如果存在,則直接返回結(jié)果
            return list;
        }
    }
    // 不使用緩存,則從數(shù)據(jù)庫中查詢
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

二級(jí)緩存key是如何生成的?

也是使用的是BaseExecutor類中的createCacheKey方法生成的,所以二級(jí)緩存key和一級(jí)緩存生成規(guī)則是一樣的。

二級(jí)緩存范圍

二級(jí)緩存有一個(gè)非常重要的空間劃分策略:

namespace="com.tian.mybatis.mappers.UserMapper"

namespace="com.tian.mybatis.mappers.RoleMapper"

即,按照namespace劃分,同一個(gè)namespace,同一個(gè)Cache空間,不同的namespace,不同的Cache空間。

比如:

總結(jié)MyBatis緩存結(jié)構(gòu)

在這個(gè)namespace下的二級(jí)緩存是同一個(gè)。

二級(jí)緩存什么時(shí)候會(huì)被清空?

每當(dāng)執(zhí)行insert、update、delete,flushCache=true時(shí),二級(jí)緩存都會(huì)被清空。

事務(wù)不提交,二級(jí)緩存不生效?

SqlSession sqlSession = sqlSessionFactory.openSession();
System.out.println("第一次查詢"); 
User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectById", 1);
System.out.println(user);

//sqlSession.commit();

SqlSession  sqlSession1 = sqlSessionFactory.openSession();
System.out.println("第二次查詢");
User  user2 = sqlSession1.selectOne("com.tian.mybatis.mapper.UserMapper.selectById", 1);
System.out.println(user2);

因?yàn)槎?jí)緩存使用的是TransactionalCaheManager(tcm)來管理的,最后又調(diào)用了TranscatinalCache的getObject()、putObject()、commit方法。

TransactionalCache里面又持有真正的Cache對(duì)象,比如:經(jīng)過層層裝飾的PrepetualCache。

在putObject的時(shí)候,只是添加到entriesToAddOnCommit里面。

//TransactionalCache類中 
@Override
public void putObject(Object key, Object object) {
    // 暫存 KV 到 entriesToAddOnCommit 中
    entriesToAddOnCommit.put(key, object);
}

只有conmit方法被調(diào)用的時(shí)候,才會(huì)調(diào)用flushPendingEntries方法,真正寫入到緩存里。DefaultSqlSession調(diào)用commit方法的時(shí)候就會(huì)調(diào)到這個(gè)commit方法。

//TransactionalCache類中   
public void commit() {
    //如果 clearOnCommit 為 true ,則清空 delegate 緩存
    if (clearOnCommit) {
      delegate.clear();
    }
    // 將 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate 中
    flushPendingEntries();
    // 重置
    reset();
  }
private void flushPendingEntries() {
    // 將 entriesToAddOnCommit 刷入 delegate 中
    for (Map.Entry entry : entriesToAddOnCommit.entrySet()) {
      delegate.putObject(entry.getKey(), entry.getValue());
    }
    // 將 entriesMissedInCache 刷入 delegate 中
    for (Object entry : entriesMissedInCache) {
      if (!entriesToAddOnCommit.containsKey(entry)) {
        delegate.putObject(entry, null);
      }
    }
}
private void reset() {
    // 重置 clearOnCommit 為 false
    clearOnCommit = false;
    // 清空 entriesToAddOnCommit、entriesMissedInCache
    entriesToAddOnCommit.clear();
    entriesMissedInCache.clear();
}

為什么增刪該操作會(huì)清空二級(jí)緩存呢?

因?yàn)樵贑achingExecutor的update方法中

@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
  flushCacheIfRequired(ms);
  return delegate.update(ms, parameterObject);
}
private void flushCacheIfRequired(MappedStatement ms) {
    Cache cache = ms.getCache();
    // 是否需要清空緩存
    //通過 @Options(flushCache = Options.FlushCachePolicy.TRUE) 或  方式,
    //開啟需要清空緩存。
    if (cache != null && ms.isFlushCacheRequired()) {
        //調(diào)用 TransactionalCache#clear() 方法,清空緩存。
        //注意,此時(shí)清空的僅僅,當(dāng)前事務(wù)中查詢數(shù)據(jù)產(chǎn)生的緩存。
        //而真正的清空,在事務(wù)的提交時(shí)。這是為什么呢?
        //還是因?yàn)槎?jí)緩存是跨 Session 共享緩存,在事務(wù)尚未結(jié)束時(shí),不能對(duì)二級(jí)緩存做任何修改。
        tcm.clear(cache);
    }
}

如何實(shí)現(xiàn)多個(gè)namespace的緩存共享?

關(guān)于多個(gè)namespace的緩存共享的問題,可以使用來解決。

比如:

cache-ref代表引用別名的命名空間的Cache配置,兩個(gè)命名空間的操作使用的是同一個(gè)Cache。在關(guān)聯(lián)的表比較少或者按照業(yè)務(wù)可以對(duì)表進(jìn)行分組的時(shí)候可以使用。

「注意」:在這種情況下,多個(gè)mapper的操作都會(huì)引起緩存刷新,所以這里的緩存的意義已經(jīng)不是很大了。

如果將第三方緩存作為二級(jí)緩存?

Mybatis除了自帶的二級(jí)換以外,我們還可以通過是想Cache接口來自定義二級(jí)緩存。

添加依賴

     
         org.mybatis.caches
         mybatis-redis
         1.0.0-beta2
    

redis基礎(chǔ)配置項(xiàng)

    host=127.0.0.1
    port=6379
    connectionTimeOut=5000
    soTimeout=5000
    datebase=0

在我們的UserMapper.xml中添加

RedisCache類圖,Cache就是Mybatis中緩存的頂層接口。

總結(jié)MyBatis緩存結(jié)構(gòu)

二級(jí)緩存應(yīng)用場(chǎng)景

對(duì)于訪問多的查詢請(qǐng)求且用戶對(duì)查詢結(jié)果實(shí)時(shí)性要求不高,此時(shí)可采用mybatis二級(jí)緩存技術(shù)降低數(shù)據(jù)庫訪問量,提高訪問速度,業(yè)務(wù)場(chǎng)景比如:耗時(shí)較高的統(tǒng)計(jì)分析sql、電話賬單查詢sql等。

緩存查詢順序

先查二級(jí)緩存,不存在則堅(jiān)持一級(jí)緩存是否關(guān)閉,沒關(guān)閉,則再查一級(jí)緩存,還不存在,最后查詢數(shù)據(jù)庫。

總結(jié)MyBatis緩存結(jié)構(gòu)

二級(jí)緩存總結(jié)

二級(jí)緩存開啟方式有兩步:

第一步:在全局配置中添加配置


    

第二步,在Mapper中添加配置

二級(jí)換是默認(rèn)開啟的,但是針對(duì)每一個(gè)Mapper的二級(jí)緩存是需要手動(dòng)開啟的。

二級(jí)緩存的key和一級(jí)緩存的key是一樣的。

每當(dāng)執(zhí)行insert、update、delete,flushCache=true時(shí),二級(jí)緩存都會(huì)被清空。

我們可以繼承第三方緩存來作為Mybatis的二級(jí)緩存。

到此,關(guān)于“總結(jié)MyBatis緩存結(jié)構(gòu)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!


當(dāng)前標(biāo)題:總結(jié)MyBatis緩存結(jié)構(gòu)
文章地址:http://weahome.cn/article/gehhgs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部