被面試官拷打 MyBatis 的多級(jí)緩存機(jī)制,這樣答就過了
共 5989字,需瀏覽 12分鐘
·
2024-06-17 13:58
上周三,小 X 去面試一家中廠,其中面試官問到 MyBatis 的多級(jí)緩存機(jī)制是怎么樣運(yùn)行的?這個(gè)問題可以好好準(zhǔn)備一下,很多人可能只會(huì)用 MyBatisPlus,簡單的多表聯(lián)查 SQL 語句可能都寫不出來,更別說索引優(yōu)化、SQL 語句優(yōu)化、安全漏洞等問題了,先打好基礎(chǔ),才能更好地學(xué)習(xí)。
題目
MyBatis 的多級(jí)緩存機(jī)制是怎么樣運(yùn)作的?
更多面試題目請見
推薦解析
一級(jí)緩存
1)MyBatis 的一級(jí)緩存默認(rèn)開啟,且默認(rèn)作用范圍為 SESSION,即一級(jí)緩存在一個(gè)會(huì)話中生效,也可以通過配置將作用范圍設(shè)置為 STATEMENT,讓一級(jí)緩存僅針對(duì)當(dāng)前執(zhí)行的 SQL 語句生效。2)在同一個(gè)會(huì)話中,執(zhí)行增,刪,改操作會(huì)使本會(huì)話中的一級(jí)緩存失效。3)不同會(huì)話持有不同的一級(jí)緩存,本會(huì)話內(nèi)的操作不會(huì)影響其它會(huì)話內(nèi)的一級(jí)緩存。
Session 針對(duì)瀏覽器會(huì)話,不同會(huì)話的同一個(gè) SQL 語句,自然是不會(huì)走一級(jí)緩存。同一個(gè)瀏覽器會(huì)話,但是查詢條件不同,比如 Where 條件不同,依然不會(huì)走一級(jí)緩存,或者同一個(gè)瀏覽器在兩個(gè)相同的查詢條件下,中間執(zhí)行了一次增、刪、改的操作,一級(jí)緩存依然失效。
特別注意:一級(jí)緩存針對(duì)的范圍是什么?以及一級(jí)緩存失效的場景,當(dāng)然一般我們都會(huì)在 yml 配置中去開啟日志,通過查看日志可以看到緩存是否被使用!
二級(jí)緩存
1) MyBatis 中的二級(jí)緩存默認(rèn)開啟,可以在 MyBatis 配置文件中的<settings>中添加<setting name="cacheEnabled" value="false"/>將二級(jí)緩存關(guān)閉;2)MyBatis 中的二級(jí)緩存作用范圍是同一命名空間下的多個(gè)會(huì)話共享,這里的命名空間就是映射文件的 namespace,即不同會(huì)話使用同一映射文件中的 SQL 語句對(duì)數(shù)據(jù)庫執(zhí)行操作并提交事務(wù)后,均會(huì)影響這個(gè)映射文件持有的二級(jí)緩存;3)MyBatis 中執(zhí)行查詢操作后,需要提交事務(wù)才能將查詢結(jié)果緩存到二級(jí)緩存中;4)MyBatis 中執(zhí)行增,刪或改操作并提交事務(wù)后,會(huì)清空對(duì)應(yīng)的二級(jí)緩存;5)MyBatis 中需要在映射文件中添加<cache>標(biāo)簽來為映射文件配置二級(jí)緩存,也可以在映射文件中添加<cache-ref>標(biāo)簽來引用其它映射文件的二級(jí)緩存以達(dá)到多個(gè)映射文件持有同一份二級(jí)緩存的效果。
二級(jí)緩存配置項(xiàng)
在 Mapper 配置文件中添加的 Cache 標(biāo)簽中可以設(shè)置相關(guān)屬性。
1)Eviction 屬性:緩存回收策略(LRU、FIFO、SOFT、WEAK)
2)FlushInterval屬性:刷新間隔,單位毫秒,默認(rèn)沒有刷新間隔,語句被調(diào)用時(shí)緩存會(huì)刷新。
3)Size:引用的數(shù)目,緩存存儲(chǔ)的對(duì)象數(shù)量,考慮到內(nèi)存溢出問題。
4)ReadOnly:只讀,是否是只讀緩存,如果為 true,所有調(diào)用者返回緩存對(duì)象的相同實(shí)例。如果為 false,會(huì)返回緩存對(duì)象的拷貝(序列化對(duì)象),性能慢,但安全性高,默認(rèn)為 false。
是否需要三級(jí)緩存?
概念:三級(jí)緩存通常指的是在分布式系統(tǒng)中,跨應(yīng)用實(shí)例的緩存層,如使用 Redis 或 Memcached 作為緩存存儲(chǔ)。
作用:三級(jí)緩存可以進(jìn)一步減少對(duì)數(shù)據(jù)庫的訪問,提高系統(tǒng)的擴(kuò)展性和性能。
考慮因素:是否需要三級(jí)緩存取決于應(yīng)用的規(guī)模、架構(gòu)和性能需求。如果應(yīng)用部署在多個(gè)服務(wù)器上,且需要共享數(shù)據(jù),可能需要考慮引入三級(jí)緩存。
實(shí)現(xiàn):三級(jí)緩存通常不是由 MyBatis 直接提供,而是通過集成外部緩存系統(tǒng)來實(shí)現(xiàn)。
應(yīng)用規(guī)模:對(duì)于大型應(yīng)用或分布式系統(tǒng),三級(jí)緩存可以提供更好的性能和擴(kuò)展性。
性能需求:如果應(yīng)用對(duì)性能有較高要求,尤其是在高并發(fā)場景下,三級(jí)緩存可以顯著減少數(shù)據(jù)庫的壓力。
數(shù)據(jù)一致性:引入三級(jí)緩存需要考慮數(shù)據(jù)一致性問題,確保緩存與數(shù)據(jù)庫之間的數(shù)據(jù)同步。
復(fù)雜性:實(shí)現(xiàn)三級(jí)緩存可能會(huì)增加系統(tǒng)的復(fù)雜性,需要權(quán)衡實(shí)現(xiàn)成本和性能收益。
其他補(bǔ)充
魚聰明 AI 的回答:
魚聰明 AI 地址:https://www.yucongming.com/
一級(jí)緩存示例:
一級(jí)緩存是自動(dòng)啟用的,不需要額外配置。它通常在 SqlSession 的生命周期內(nèi)有效。
// 獲取 SqlSession
SqlSession session = sqlSessionFactory.openSession();
try {
// 查詢用戶,一級(jí)緩存會(huì)自動(dòng)存儲(chǔ)這個(gè)查詢結(jié)果
User user1 = session.selectOne("com.example.mapper.User.selectById", 1L);
// 再次查詢相同的用戶,這次將從一級(jí)緩存中獲取結(jié)果
User user2 = session.selectOne("com.example.mapper.User.selectById", 1L);
// 檢驗(yàn)緩存是否失效:在一級(jí)緩存中,可以通過比較 user1 和 user2 是否相同來檢驗(yàn)
if (user1 == user2) {
System.out.println("一級(jí)緩存有效");
} else {
System.out.println("一級(jí)緩存失效");
}
} finally {
session.close(); // 關(guān)閉 SqlSession,結(jié)束一級(jí)緩存的生命周期
}
二級(jí)緩存示例:
二級(jí)緩存需要在 MyBatis 配置文件中配置,并在 Mapper 接口上使用 @CacheNamespace 注解。
<!-- mybatis-config.xml -->
<configuration>
<settings>
<!-- 啟用二級(jí)緩存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 配置二級(jí)緩存的類型,這里使用 MyBatis 內(nèi)置的 PerpetualCache -->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache">
<!-- 二級(jí)緩存的大小限制 -->
<property name="size" value="1024"/>
</cache>
</configuration>
// 在 Mapper 接口上使用 @CacheNamespace 注解
@CacheNamespace
public interface UserMapper {
User selectById(Long id);
}
// 使用二級(jí)緩存的示例
SqlSession session = sqlSessionFactory.openSession();
try {
// 查詢用戶,結(jié)果將被存儲(chǔ)在二級(jí)緩存中
User user1 = session.getMapper(UserMapper.class).selectById(1L);
// 關(guān)閉當(dāng)前會(huì)話,然后重新打開一個(gè)新的會(huì)話
session.close();
session = sqlSessionFactory.openSession();
// 在新的會(huì)話中再次查詢相同的用戶,這次將從二級(jí)緩存中獲取結(jié)果
User user2 = session.getMapper(UserMapper.class).selectById(1L);
// 檢驗(yàn)緩存是否失效:在二級(jí)緩存中,可以通過比較 user1 和 user2 是否相同來檢驗(yàn)
if (user1 == user2) {
System.out.println("二級(jí)緩存有效");
} else {
System.out.println("二級(jí)緩存失效");
}
} finally {
session.close(); // 關(guān)閉 SqlSession
}
檢驗(yàn)緩存是否失效:
-
一級(jí)緩存:由于一級(jí)緩存僅在 SqlSession的生命周期內(nèi)有效,通常不需要手動(dòng)檢驗(yàn)緩存是否失效。當(dāng)SqlSession關(guān)閉時(shí),一級(jí)緩存自動(dòng)失效。 -
二級(jí)緩存:可以通過比較兩次查詢返回的對(duì)象引用是否相同來檢驗(yàn)緩存是否失效。如果相同,說明緩存有效;如果不同,說明緩存可能已經(jīng)失效。
歡迎交流
本文主要介紹 MyBatis 的一二級(jí)緩存和緩存失效的主要場景,以及是否需要三級(jí)緩存的問題,關(guān)于數(shù)據(jù)庫方面是一個(gè)重點(diǎn)項(xiàng),因?yàn)椴煌Z言都需要利用數(shù)據(jù)庫進(jìn)行持久化存儲(chǔ),無論哪種 ORM 框架都有各自的優(yōu)缺點(diǎn),需要根據(jù)實(shí)際場景進(jìn)行選擇,在文末還有三個(gè)提問,歡迎小伙伴在評(píng)論區(qū)進(jìn)行留言!近期面試鴨小程序已全面上線,想要刷題的小伙伴可以積極參與!
1)一級(jí)緩存和二級(jí)緩存的區(qū)別是什么?
2)如何配置和管理二級(jí)緩存?
3)MyBatis的一級(jí)緩存是如何工作的?它的生命周期是什么時(shí)候開始和結(jié)束的?什么情況下會(huì)導(dǎo)致一級(jí)緩存的失效或刷新?
點(diǎn)燃求職熱情!每周持續(xù)更新,海量面試題和大廠面經(jīng)等你挑戰(zhàn)!趕緊關(guān)注面試鴨公眾號(hào),輕松備戰(zhàn)秋招和暑期實(shí)習(xí)!
往期推薦
小黑子!微服務(wù)鏈路追蹤都不知道?
關(guān)于 Bean 容器的注入方式,99 % 的人都答不全!
SpringBoot 同時(shí)可以處理多少請求?這可難倒了不少人
慢 SQL 監(jiān)控都不會(huì)?Out!
面試官:Spring Bean 的生命周期都不會(huì),你走吧下一位
面試官說要壓測我的網(wǎng)站,我被壓力了!
