帶你深入理解MyBatis緩存機(jī)制
一、簡(jiǎn)介
1、緩存機(jī)制介紹
當(dāng)客戶端發(fā)起一次查詢請(qǐng)求時(shí),首先通過java程序進(jìn)行網(wǎng)絡(luò)傳輸訪問mysql數(shù)據(jù)庫及對(duì)應(yīng)的數(shù)據(jù)的服務(wù)器硬盤,當(dāng)?shù)诙蔚恼?qǐng)求也是查詢相同的數(shù)據(jù)時(shí)再通過這個(gè)流程顯然有點(diǎn)“浪費(fèi)”上次請(qǐng)求訪問到的資源,所以我們將第一次查詢到的數(shù)據(jù)存到緩存區(qū)域,當(dāng)發(fā)生下一次相同請(qǐng)求時(shí)直接在緩存區(qū)域拿就行了。
2. 一級(jí)緩存和二級(jí)緩存
①使用順序
查詢的順序是:
- 先查詢二級(jí)緩存,因?yàn)槎?jí)緩存中可能會(huì)有其他程序已經(jīng)查出來的數(shù)據(jù),可以拿來直接使用。
- 如果二級(jí)緩存沒有命中,再查詢一級(jí)緩存
- 如果一級(jí)緩存也沒有命中,則查詢數(shù)據(jù)庫
- SqlSession關(guān)閉之前,一級(jí)緩存中的數(shù)據(jù)會(huì)寫入二級(jí)緩存
②效用范圍
一級(jí)緩存:SqlSession級(jí)別二級(jí)緩存:SqlSessionFactory級(jí)別
它們之間范圍的大小參考下面圖:
二、一級(jí)緩存
當(dāng)使用相同查詢條件查詢數(shù)據(jù)時(shí),一共只打印了一條SQL語句,兩個(gè)變量指向同一個(gè)對(duì)象。
一級(jí)緩存失效的情況:
- 不是同一個(gè)SqlSession
- 同一個(gè)SqlSession但是查詢條件發(fā)生了變化
- 同一個(gè)SqlSession兩次查詢期間執(zhí)行了任何一次增刪改操作
- 同一個(gè)SqlSession兩次查詢期間手動(dòng)清空了緩存
- 同一個(gè)SqlSession兩次查詢期間提交了事務(wù)
三、二級(jí)緩存
3.1 mybatis自帶的二級(jí)緩存
3.1.1 代碼測(cè)試二級(jí)緩存
① 開啟二級(jí)緩存功能
在想要使用二級(jí)緩存的Mapper配置文件中加入cache標(biāo)簽
<mapper namespace="com.zengchuiyu.mybatis.dao.EmployeeMapper"> <!-- 啟動(dòng)二級(jí)緩存功能 --> <cache/>
②讓實(shí)體類支持序列化
public class Employee implements Serializable {
③junit測(cè)試
這個(gè)功能的測(cè)試操作需要將SqlSessionFactory對(duì)象設(shè)置為成員變量
public class CacheTest { private SqlSessionFactory factory; @Before public void init() throws IOException { factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")); } //測(cè)試二級(jí)緩存,(mybatis自帶的) @Test public void test1(){ SqlSession session = factory.openSession(); EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); Employee employee = mapper.selectEmpById(2); System.out.println("employee = " + employee); //在執(zhí)行第二次查詢前,關(guān)閉當(dāng)前SqlSession session.close(); //開啟新的SqlSession session = factory.openSession(); mapper = session.getMapper(EmployeeMapper.class); employee = mapper.selectEmpById(2); System.out.println("employee = " + employee); session.close(); } }
打印效果:
22:48:18.669 [main] DEBUG com.zengchuiyu.mybatis.dao.EmployeeMapper - Cache Hit Ratio [com.zengchuiyu.mybatis.dao.EmployeeMapper]: 0.5
④緩存命中率
日志中打印的Cache Hit Ratio叫做緩存命中率
Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.0(0/1) Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.5(1/2) Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.6666666666666666(2/3) Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.75(3/4) Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.8(4/5)
緩存命中率=命中緩存的次數(shù)/查詢的總次數(shù)
3.1.2 查詢結(jié)果存入二級(jí)緩存的時(shí)機(jī)
結(jié)論:SqlSession關(guān)閉的時(shí)候,一級(jí)緩存中的內(nèi)容會(huì)被存入二級(jí)緩存
3.1.3 二級(jí)緩存相關(guān)配置
- eviction屬性:緩存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
FIFO(First in First out) – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來移除它們。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象。
默認(rèn)的是 LRU。
- flushInterval屬性:刷新間隔,單位毫秒
默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔,緩存僅僅調(diào)用語句時(shí)刷新
- size屬性:引用數(shù)目,正整數(shù)
代表緩存最多可以存儲(chǔ)多少個(gè)對(duì)象,太大容易導(dǎo)致內(nèi)存溢出
- readOnly屬性:只讀,true/false
true:只讀緩存;會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例。因此這些對(duì)象不能被修改。這提供了很重要的性能優(yōu)勢(shì)。
false:讀寫緩存;會(huì)返回緩存對(duì)象的拷貝(通過序列化)。這會(huì)慢一些,但是安全,因此默認(rèn)是 false。
四、整合EHCache
4.1 EHCache簡(jiǎn)介
官網(wǎng)地址:https://www.ehcache.org/
Ehcache is an open source, standards-based cache that boosts performance, offloads your database, and simplifies scalability. It's the most widely-used Java-based cache because it's robust, proven, full-featured, and integrates with other popular libraries and frameworks. Ehcache scales from in-process caching, all the way to mixed in-process/out-of-process deployments with terabyte-sized caches.
Ehcache是一個(gè)開源的,基于標(biāo)準(zhǔn)的緩存,可以提高性能,卸載數(shù)據(jù)庫,簡(jiǎn)化可伸縮性。它是最廣泛使用的基于java的緩存,因?yàn)樗?、可靠、功能齊全,并與其他流行的庫和框架集成。Ehcache從進(jìn)程內(nèi)緩存擴(kuò)展到具有tb大小緩存的進(jìn)程內(nèi)/進(jìn)程外混合部署。
4.2 整合操作
①M(fèi)ybatis環(huán)境
在Mybatis環(huán)境下整合EHCache,前提當(dāng)然是要先準(zhǔn)備好Mybatis的環(huán)境。
②添加依賴
依賴信息:
<!-- Mybatis EHCache整合包 --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version> </dependency> <!-- slf4j日志門面的一個(gè)具體實(shí)現(xiàn) --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
依賴傳遞情況:
各主要jar包作用
jar包名稱 | 作用 |
---|---|
mybatis-ehcache | Mybatis和EHCache的整合包 |
ehcache | EHCache核心包 |
slf4j-api | SLF4J日志門面包 |
logback-classic | 支持SLF4J門面接口的一個(gè)具體實(shí)現(xiàn) |
③整合EHCache
[1]創(chuàng)建EHCache配置文件
ehcache.xml
[2]文件內(nèi)容
<?xml version="1.0" encoding="utf-8" ?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盤保存路徑 --> <diskStore path="D:\zengchuiyu\ehcache"/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
引入第三方框架或工具時(shí),配置文件的文件名可以自定義嗎?
可以自定義:文件名是由我告訴其他環(huán)境
不能自定義:文件名是框架內(nèi)置的、約定好的,就不能自定義,以避免框架無法加載這個(gè)文件
④加入logback日志
存在SLF4J時(shí),作為簡(jiǎn)易日志的log4j將失效,此時(shí)我們需要借助SLF4J的具體實(shí)現(xiàn)logback來打印日志。
[1]各種Java日志框架簡(jiǎn)介
門面:
名稱 | 說明 |
---|---|
JCL(Jakarta Commons Logging) | 陳舊 |
SLF4J(Simple Logging Facade for Java)★ | 適合 |
jboss-logging | 特殊專業(yè)領(lǐng)域使用 |
實(shí)現(xiàn):
名稱 | 說明 |
---|---|
log4j★ | 最初版 |
JUL(java.util.logging) | JDK自帶 |
log4j2 | Apache收購log4j后全面重構(gòu),內(nèi)部實(shí)現(xiàn)和log4j完全不同 |
logback★ | 優(yōu)雅、強(qiáng)大 |
注:標(biāo)記★的技術(shù)是同一作者。
[2]logback配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <!-- 指定日志輸出的位置 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- 日志輸出的格式 --> <!-- 按照順序分別是:時(shí)間、日志級(jí)別、線程名稱、打印日志的類、日志主體內(nèi)容、換行 --> <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern> </encoder> </appender> <!-- 設(shè)置全局日志級(jí)別。日志級(jí)別按順序分別是:DEBUG、INFO、WARN、ERROR --> <!-- 指定任何一個(gè)日志級(jí)別都只打印當(dāng)前級(jí)別和后面級(jí)別的日志。 --> <root level="DEBUG"> <!-- 指定打印日志的appender,這里通過“STDOUT”引用了前面配置的appender --> <appender-ref ref="STDOUT" /> </root> <!-- 根據(jù)特殊需求指定局部日志級(jí)別 --> <logger name="com.atguigu.crowd.mapper" level="DEBUG"/> </configuration>
⑤ EHCache配置文件說明
當(dāng)借助CacheManager.add(“緩存名稱”)創(chuàng)建Cache時(shí),EhCache便會(huì)采用指定的的管理策略。
defaultCache標(biāo)簽各屬性說明:
五、緩存基本原理
5.1 Cache接口
① 頂級(jí)接口
org.apache.ibatis.cache.Cache接口:所有緩存都必須實(shí)現(xiàn)的頂級(jí)接口
② Cache接口中的方法
③ 緩存的本質(zhì)
根據(jù)Cache接口中方法的聲明我們能夠看到,緩存的本質(zhì)是一個(gè)Map。
5.2 PerpetualCache
org.apache.ibatis.cache.impl.PerpetualCache是Mybatis的默認(rèn)緩存,也是Cache接口的默認(rèn)實(shí)現(xiàn)。Mybatis一級(jí)緩存和自帶的二級(jí)緩存都是通過PerpetualCache來操作緩存數(shù)據(jù)的。但是這就奇怪了,同樣是PerpetualCache這個(gè)類,怎么能區(qū)分出來兩種不同級(jí)別的緩存呢?
其實(shí)很簡(jiǎn)單,調(diào)用者不同。
一級(jí)緩存:由BaseExecutor調(diào)用PerpetualCache
二級(jí)緩存:由CachingExecutor調(diào)用PerpetualCache,而CachingExecutor可以看做是對(duì)BaseExecutor的裝飾
總結(jié)
到此這篇關(guān)于MyBatis緩存機(jī)制的文章就介紹到這了,更多相關(guān)MyBatis緩存機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java調(diào)用阿里身份證實(shí)現(xiàn)驗(yàn)證接口
這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用阿里身份證實(shí)現(xiàn)驗(yàn)證接口,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-06-06使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信
這篇文章主要介紹了使用Java實(shí)現(xiàn)簡(jiǎn)單串口通信,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07js中去除字符串中所有的html標(biāo)簽代碼實(shí)例
這篇文章主要介紹了js中去除字符串中所有的html標(biāo)簽代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08java 工廠模式的講解及優(yōu)缺點(diǎn)的介紹
這篇文章主要介紹了java 工廠模式的講解及優(yōu)缺點(diǎn)的介紹的相關(guān)資料, 簡(jiǎn)單工廠模式,又稱為靜態(tài)工廠方法(Static Factory Method)模式,它屬于類創(chuàng)建型模式,需要的朋友可以參考下2017-08-08Spring?Boot使用Hibernate-Validator校驗(yàn)參數(shù)時(shí)的長(zhǎng)度校驗(yàn)方法詳解
這篇文章主要給大家介紹了關(guān)于Spring?Boot使用Hibernate-Validator校驗(yàn)參數(shù)時(shí)的長(zhǎng)度校驗(yàn)方法的相關(guān)資料,在Spring Boot中可以使用Spring Boot Validation來對(duì)參數(shù)名稱進(jìn)行校驗(yàn),需要的朋友可以參考下2023-08-08Java 獲取本機(jī)的IP與MAC地址實(shí)現(xiàn)詳解
這篇文章主要介紹了Java 獲取本機(jī)的IP與MAC地址實(shí)現(xiàn)詳解的相關(guān)資料,需要的朋友可以參考下2016-09-09spring-boot中spring-boot-maven-plugin報(bào)紅錯(cuò)誤及解決
這篇文章主要介紹了spring-boot中spring-boot-maven-plugin報(bào)紅錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03