MyBatis驗(yàn)證多級(jí)緩存及 Cache Aside 模式的應(yīng)用小結(jié)
前言
MyBatis 官方文檔 中文版本沒(méi)有翻譯cache的部分,網(wǎng)上資料比較雜。
這里使用 Spock 測(cè)試框架驗(yàn)證下多級(jí)緩存,并探索 Mybatis 的 CacheAside 模式。注意:
- 本文用 本地緩存 表示一級(jí)緩存,全局緩存 表示二級(jí)緩存
- 用例倉(cāng)庫(kù)
1. 多級(jí)緩存的概念
多級(jí)緩存可以聯(lián)系CPU的結(jié)構(gòu),離核心約近的一致性越高。
1.1 CPU 多級(jí)緩存
1.2 MyBatis 多級(jí)緩存
本地緩存默認(rèn)開(kāi)啟,全局緩存需要使用 <cache/>
開(kāi)啟
By default, just local session caching is enabled that is used solely to cache data for the duration of a session. To enable a global second level of caching you simply need to add one line to your SQL Mapping file:
<mapper namespace="com.james.mapper.FileCacheMapper"> <cache/> <!-- 聲明該標(biāo)簽,全局緩存開(kāi)啟 --> <select id="select" resultType="java.lang.String"> SELECT file_name FROM file </select> </mapper>
2. MyBatis 本地緩存
用 Spring 注入的 mapper,調(diào)用一次select方法就會(huì)產(chǎn)生一個(gè) sqlSession,沒(méi)有利用到本地緩存。
def "未使用事務(wù),第二次查詢,不命中本地緩存"() { given: def list1 = mapper.select() def list2 = mapper.select() expect: list1 !== list2 }
用事務(wù)包裹后,兩次 select 共用一個(gè) sqlSession,緩存命中
def "使用事務(wù),命中緩存"() { given: def list1 = [] def list2 = [] when: transaction.execute { list1 = mapper.select() list2 = mapper.select() } then: // 同一個(gè)事務(wù)使用同一個(gè)SqlSession,若引用相同則認(rèn)為命中緩存 list1 === list2 }
note: groovy 中
list1 === list2
表示引用相同,list1 == list2
表示兩個(gè)列表的內(nèi)容相同
3. MyBatis 全局緩存
上文說(shuō)到,沒(méi)有事務(wù)保護(hù)的 select方法調(diào)用無(wú)法公用一個(gè) sqlSession,所以利用不了本地緩存。
全局緩存的范圍更大,只要是同一個(gè)mapper的調(diào)用,都會(huì)被緩存。
def "全局緩存默認(rèn)關(guān)閉,需要在xml文件中使用 <cache/> 標(biāo)簽啟用"() { given: def list1 = fileCacheMapper.select() def list2 = fileCacheMapper.select() expect: // 由于 SerializedCache.java:64 使用的是由byte[]序列化方式存儲(chǔ)元素,所以實(shí)例的地址必然不同 list1 !== list2 list1 == list2 }
3.1 MyBatis 全局緩存過(guò)期算法
值得關(guān)注的是 SOFT 和 WEAK 的類型,對(duì)應(yīng)Java中軟引用和弱引用。
軟引用是在內(nèi)存不足時(shí)GC可以回收,弱引用是下次GC即可回收(比軟引用)積極。
3.2 CacheAside 模式
以下是 Mybatis 默認(rèn)的全局緩存失效模式,也就是 Cache Aside 模式的應(yīng)用。
- 查詢的時(shí)候,如果沒(méi)有緩存,則寫入。
- 任何數(shù)據(jù)操作,使緩存失效。
<select ... flushCache="false" useCache="true"/> <insert ... flushCache="true"/> <update ... flushCache="true"/> <delete ... flushCache="true"/>
后記
Cache Aside 并不能保證強(qiáng)一致性,不然也就不會(huì)有 Paxos 這種復(fù)雜的共識(shí)算法了。 —— 《鳳凰架構(gòu)》
MyBatis 提供了緩存切口, 采用 Redis 會(huì)引入什么問(wèn)題?
- 多實(shí)例之間緩存重復(fù)的失效問(wèn)題,查詢時(shí)競(jìng)爭(zhēng)寫緩存的問(wèn)題。
- ORM框架與中間件耦合,違反單一職責(zé)。
萬(wàn)一遇到需強(qiáng)一致場(chǎng)景,如何增強(qiáng)?
兩個(gè)查詢請(qǐng)求同時(shí)到來(lái),此時(shí)緩存為空,需要將MySql數(shù)據(jù)寫入緩存。此時(shí)會(huì)出現(xiàn)競(jìng)爭(zhēng)寫緩存的情況。用寫鎖來(lái)保證緩存內(nèi)的數(shù)據(jù)跟數(shù)據(jù)庫(kù)保持一致。
public void query() { if (cache 命中) { retrun cache } 獲取緩存寫鎖 if (獲取鎖失敗) { return 查數(shù)據(jù)庫(kù) } 查數(shù)據(jù)庫(kù) 寫緩存 釋放緩存寫鎖 }
到此這篇關(guān)于MyBatis驗(yàn)證多級(jí)緩存及 Cache Aside 模式的應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)MyBatis驗(yàn)證多級(jí)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Calendar類常用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
從JDK1.1版本開(kāi)始,在處理日期和時(shí)間時(shí),系統(tǒng)推薦使用Calendar類進(jìn)行實(shí)現(xiàn)。接下來(lái)通過(guò)實(shí)例代碼給大家詳細(xì)介紹Java Calendar類相關(guān)知識(shí),需要的朋友參考下吧2017-04-04Java并發(fā)容器相關(guān)知識(shí)總結(jié)
今天給大家?guī)?lái)的文章是Java并發(fā)容器的相關(guān)知識(shí),文中有非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)Java并發(fā)容器的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法
平時(shí)對(duì)接口時(shí),經(jīng)常遇到j(luò)son字符串和map對(duì)象之間的交互,這篇文章主要給大家介紹了關(guān)于Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07Spring實(shí)現(xiàn)Logback日志模板設(shè)置動(dòng)態(tài)參數(shù)功能
本文介紹如何在Spring應(yīng)用中實(shí)現(xiàn)Logback日志模板的動(dòng)態(tài)參數(shù)設(shè)置,通過(guò)設(shè)計(jì)traceId鏈路標(biāo)識(shí),將其動(dòng)態(tài)添加到日志輸出中,從而實(shí)現(xiàn)簡(jiǎn)易的鏈路追蹤功能,感興趣的朋友跟隨小編一起看看吧2024-11-11Springmvc conver實(shí)現(xiàn)原理及用法解析
這篇文章主要介紹了Springmvc conver實(shí)現(xiàn)原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10