Mybatis07-緩存

一、緩存機制的原理

計算機每次從mysql中執行sql語句,都是內存與硬盤的通信,對計算機來說,影響效率。

因此使用緩存機制。

?

1-1、MyBatis 的緩存機制:

執行 DQL(select 語句)的時候,將查詢結果放到緩存當中(內存當中),如果下一次還是執行完全相同的 DQL(select 語句)語句,直接從緩存中拿數據,不再查數據庫了。不再去硬盤上找數據了。

示例:

第一次執行這個 SQL:

select * from t_car where id=1;

第二次還是執行這個 SQL,完全一樣:

select * from t_car where id=1;

此時,從緩存中獲取,不再查數據庫了。

當兩條sql語句之間,對數據庫做了任何修改操作,緩存將從內存中清除。

目的:提高執行效率。

緩存機制:使用減少 IO 的方式來提高效率。

IO:讀文件和寫文件。

緩存通常是我們程序開發中優化程序的重要手段:

  • 字符串常量池
  • 整數型常量池
  • 線程池
  • 連接池
  • ……

【小結】:

????????緩存(cache)就是內存,提前把數據放到內存中,下一次用的時候,直接從緩存中拿,效率高!

二、幾種常見的緩存/池化技術

這些“池”技術,其實都是 Java 中的 緩存/復用機制,目的是:提升性能、減少資源消耗、避免頻繁創建和銷毀對象。下面來系統講解幾種常見的緩存/池化技術:


2-1、字符串常量池(String Constant Pool)

1、原理:

Java 中字符串是不可變的(final,所以 JVM 會把相同的字符串常量只保留一份副本,存放在一個稱為 字符串常量池 的內存區域。

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
  • "hello" 是一個字符串字面量,保存在常量池中

  • s1 和 s2 都指向同一個地址

2、注意:

String s3 = new String("hello");
System.out.println(s1 == s3); // false(堆 vs 常量池)

如果你想把 new 出來的字符串放入常量池:

String interned = s3.intern();
System.out.println(s1 == interned); // true

?

2-2、整數型常量池(Integer Cache)

1、原理:

Java 對于包裝類型 Integer,有一個緩存區[-128, 127]),當你使用 valueOf() 方法創建時,會從緩存中取對象而不是創建新對象。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(緩存)Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(未緩存)

2、范圍:

JVM 默認緩存范圍為 [-128, 127],可以通過啟動參數修改

-XX:AutoBoxCacheMax=300

2-3、線程池(Thread Pool)

1、原理:

線程的創建與銷毀成本高(涉及操作系統資源),頻繁創建新線程會拖慢系統。

所以,線程池把線程復用起來,讓多個任務共享固定線程,提高并發效率。

2、常用方式:

        // 創建固定大小為 3 的線程池ExecutorService pool = Executors.newFixedThreadPool(3);// 模擬提交 5 個任務for (int i = 1; i <= 15; i++) {int taskId = i;pool.submit(new Runnable() {public void run() {String threadName = Thread.currentThread().getName();System.out.println("任務 " + taskId + " 開始,線程:" + threadName);try {Thread.sleep(20000); // 模擬任務耗時} catch (InterruptedException e) {e.printStackTrace();}System.out.println("任務 " + taskId + " 結束,線程:" + threadName);}});}// 關閉線程池(注意不是立刻關閉)pool.shutdown();

打印結果:?

?

可以看到線程是復用的。

Executors 提供常見線程池工廠方法:

  • newFixedThreadPool(n)

  • newCachedThreadPool()

  • newSingleThreadExecutor()

  • newScheduledThreadPool(n)


2-4、連接池(Connection Pool)

1、?原理:

數據庫連接創建代價高(要連接服務器、授權、建會話),所以使用連接池 復用已建立的連接

2、常見實現:

  • HikariCP(Spring Boot 默認)

  • DBCP

  • C3P0

  • Druid

3、示例(Spring Boot):

spring.datasource.hikari.maximum-pool-size: 10

應用啟動后,會提前建立 10 個連接,放入連接池,供業務查詢復用。


2-5、對象池(Object Pool)

對于那些頻繁使用又比較重量級的對象(如:ByteBuffer, Socket, 數據庫連接),也可以池化處理。

Java 標準庫沒有通用的 ObjectPool,但 Apache Commons Pool 提供支持。

GenericObjectPool<MyReusableObject> pool = new GenericObjectPool<>(new MyObjectFactory());MyReusableObject obj = pool.borrowObject(); // 借
obj.doSomething();                          // 用
pool.returnObject(obj);                     // 還

你需要在項目中引入 Apache Commons Pool 的依賴(如果用 Maven):

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.11.1</version> <!-- 可根據需要換版本 -->
</dependency>

?


2-6、內存緩存(如 LRU 緩存)

Java 中可以自己實現緩存算法(如 LRU),也可以使用:

  • Guava Cache

  • Caffeine(高性能)

  • Ehcache

  • Redis(分布式)

示例(Caffeine):

Cache<String, Object> cache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES).build();

2-7、類加載緩存(ClassLoader)

JVM 對每個類只加載一次,會將 .class 文件緩存到內存中,后續實例化只需創建對象而不重復加載。


2-8、反射緩存(Method/Field 緩存)

使用反射獲取字段/方法(如 Class.getDeclaredMethods())是慢操作。JVM 會自動緩存這些反射結構,Spring、MyBatis 等框架也會自己做緩存。


2-9、JVM 運行時常見緩存(底層)

緩存類型說明
字符串常量池復用 String 常量
Integer 緩存避免頻繁裝箱創建 Integer
Class 常量池常量值如 final 字段、枚舉等
方法句柄緩存JVM 優化調用性能
Lambda 表達式緩存編譯后只創建一次匿名類對象

2-10、總結對比表

技術名稱類型緩存對象控制方式是否可配置
字符串常量池編譯期/運行期String自動/intern()?
Integer 緩存運行期Integer自動/valueOf()?
線程池并發ThreadExecutors?
連接池IO資源DB連接DataSource?
ObjectPool自定義業務對象Apache Commons?
Guava/Caffeine本地緩存任意對象API構建?
Redis分布式緩存任意對象客戶端控制?

三、Mybatis的緩存

mybatis 緩存包括:

  • 一級緩存:將查詢到的數據存儲到 SqlSession 中。
  • 二級緩存:將查詢到的數據存儲到 SqlSessionFactory 中。
  • 集成其它第三方的緩存:比如 EhCache【Java 語言開發的】、Memcache【C 語言開發的】等。

SqlSessionFactory是一個數據庫一個,SqlSession作用域是當前的sql會話。

緩存只針對DQL語句,也就是說:緩存只針對select語句!

?

3-1、MyBatis 一級緩存

3-1-1、什么是一級緩存?

一級緩存是 MyBatis 的默認緩存機制,作用范圍是 一次 SqlSession 內部。簡單說:

同一個 SqlSession 中,相同的查詢語句和參數,MyBatis 會從緩存中取數據,不會再次訪問數據庫

一級緩存mybatis默認開啟,不需要任何配置!


3-1-2、一級緩存工作流程圖

SqlSession├── 查詢語句 1(未命中緩存) → 查數據庫,緩存結果├── 查詢語句 1(再次執行) → 命中緩存,直接返回└── SqlSession.close() → 緩存銷毀

3-1-3、一級緩存使用示例

@Test
public void testFirstLevelCache() {SqlSession session = sqlSessionFactory.openSession();UserMapper mapper = session.getMapper(UserMapper.class);// 第一次查詢,去數據庫User u1 = mapper.selectById(1L);System.out.println("第一次查詢:" + u1);// 第二次查詢相同 ID,命中緩存User u2 = mapper.selectById(1L);System.out.println("第二次查詢:" + u2);System.out.println(u1 == u2); // true(同一個對象)session.close();
}

【注意】:

此時,控制臺只執行一條sql select語句!?


?

3-1-4、哪些情況會導致緩存失效?

  1. SqlSession 不是同一個

    每次 openSession() 創建新的 Session,緩存就不同。

    示例:

        @Testpublic void testFirstCache2() throws IOException {SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);Car car1 = mapper1.selectOneById(1L);System.out.println(car1);SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);Car car2 = mapper2.selectOneById(1L);System.out.println(car2);sqlSession1.close();sqlSession2.close();}

    此時,控制臺會打印兩條sql select語句。

  2. 執行了 update / insert / delete 操作

    寫操作會清空緩存(保證數據一致性),修改任意一張表,都會清空緩存!

  3. 手動清空緩存

    session.clearCache();
    
  4. 查詢的 SQL 或參數不同


?

3-1-5、一級緩存原理簡述

  • MyBatis 內部維護了一個 PerpetualCacheHashMap 實現)

  • 每次查詢前會根據 SQL+參數,生成 key,先查緩存

  • 如果命中,直接返回

  • 如果沒命中,查數據庫并存入緩存

3-2、MyBatis 二級緩存

MyBatis 的二級緩存,這對優化多次查詢、減少數據庫壓力非常重要,尤其是跨 SqlSession 的查詢場景


?

3-2-1、什么是二級緩存?

二級緩存是 MyBatis 提供的跨 SqlSession 的緩存機制。

它的作用范圍是:Mapper 映射級別(namespace)不同 SqlSession 之間共享緩存數據


3-2-2、一級 vs 二級緩存對比

對比項一級緩存(默認)二級緩存(需開啟)
緩存范圍單個 SqlSession 內多個 SqlSession 共享
默認狀態開啟默認關閉
生命周期SqlSession 生命周期應用級、映射器級別
存儲結構基于 HashMap(PerpetualCache)可自定義實現
典型用途同一次操作內避免重復查詢緩解高頻讀操作數據庫壓力

3-2-3、使用二級緩存的三步配置


Step 1:開啟全局二級緩存
<settings><setting name="cacheEnabled" value="true"/>
</settings>

【注意】:

是的,<setting name="cacheEnabled" value="true"/> 在 MyBatis 中默認就是開啟。?


Step 2:在 Mapper 映射文件中開啟 <cache/>

例如:UserMapper.xml

<mapper namespace="com.example.mapper.UserMapper"><cache /><select id="selectById" resultType="User">SELECT * FROM users WHERE id = #{id}</select>
</mapper>
  • 你也可以配置更多參數(見下方擴展)


Step 3:實體類實現 Serializable 接口(因為緩存需要序列化)
public class User implements Serializable {private Long id;private String name;// ...其他字段
}

3-2-4、二級緩存使用示例

示例1:沒有使用二級緩存

示例2:數據從二級緩存中獲取

sqlSession1關閉,數據保存到二級緩存中,再執行sqlSession2中的select語句,會從二級緩存中獲取。

【注意】:

一級緩存的優先級高,先從一級緩存中取數據,若是一級緩存關閉,則從二級中取數據!

?

示例3:跨namespace測試二級緩存

【注意】:

兩個mapper不一樣,但是執行的select語句和參數都是一樣的,但是控制臺依舊會執行兩條select查詢語句,說明二級緩存不能跨namespace!


3-2-5、哪些操作會清空二級緩存?

  • 對該 namespace 進行了 update/insert/delete(增、刪、改)

  • 顯式調用了 clearCache()

  • 配置 <cache flushInterval="..."/> 自動過期

  • 跨 namespace 無法共享(除非手動自定義)


3-2-6、常見 <cache> 配置項

<cache eviction="LRU"               <!-- 緩存淘汰策略:LRU, FIFO, SOFT, WEAK -->flushInterval="60000"        <!-- 自動刷新間隔:毫秒;刷新后二級緩存失效 -->size="512"                   <!-- 最大緩存對象數量 -->readOnly="false"             <!-- 是否只讀(只讀更快但不可修改), car1 == car2 -->blocking="true"              <!-- 防止緩存擊穿 -->
/>

?

3-2-7、一級緩存 vs 二級緩存(圖解理解)

+------------------------+
| SqlSession A           |
|  └── 一級緩存(僅自己用)     |
|                        |
| SqlSession B           |
|  └── 一級緩存(僅自己用)     |
+------------------------+↓(關閉 SqlSession 后)
+------------------------+
|     二級緩存(共享)          |
|     key: SQL + 參數          |
|     value: 查詢結果對象      |
+------------------------+

3-3、自定義緩存實現(可選)

MyBatis 允許你自定義二級緩存邏輯(如整合 Redis),也就是集成第三方的緩存組件。

【注意】:

MyBatis的一級緩存是不可替代的!集成第三方的緩存組件,替代的是二級緩存!

MyBatis 如何集成第三方緩存組件,比如 Redis、EhCache、Caffeine 等。這種方式可以將 MyBatis 的二級緩存升級為分布式或高性能緩存,實現更強的可擴展性與性能提升。?

1、示例:集成EhCache?

step1:pom.xml中添加依賴
<!-- MyBatis 對 EhCache 的支持 -->
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.2.1</version>
</dependency>

step2:?添加 ehcache.xml 配置文件
<ehcache><cache name="com.example.mapper.UserMapper"maxEntriesLocalHeap="1000"timeToLiveSeconds="600"/>
</ehcache>

step3: 在對應的xxxMapper.xml 中配置:

step4: 編寫測試類

測試類和測試二級緩存一樣,沒有變動!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89757.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89757.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89757.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【機器學習深度學習】LoRA 與 QLoRA:大模型高效微調的進階指南

目錄 前言 一、LoRA&#xff1a;低秩微調的經典之作 二、QLoRA&#xff1a;效率與精度的升級版 三、LoRA vs QLoRA&#xff1a;如何選擇&#xff1f; 3.1 性能維度對比 3.2 根據「顯卡資源」選擇 3.3 根據「任務類型與目標」選擇 3.4 根據「模型規模」選擇 3.5 根據…

教育行業網絡升級最佳實踐:SD-WAN、傳統方案與混合方案對比分析

隨著教育行業的數字化轉型不斷深入&#xff0c;網絡的穩定性、靈活性和安全性成為各類教育應用&#xff08;如遠程課堂、智慧校園和教育云平臺&#xff09;的核心支撐。然而&#xff0c;傳統的 MPLS 專線方案成本高、擴展性差&#xff0c;而純 SD-WAN 的方案在極高可靠性要求的…

[黑馬頭條]-文章列表加載

目錄 1.1)需求分析 1.2)表結構分析 ap_article 文章基本信息表 ap_article_config 文章配置表 ap_article_content 文章內容表 導入文章數據庫 實現思路 接口定義 功能實現 定義接口 編寫mapper文件 編寫業務層代碼 實現類&#xff1a; 定義常量類 編寫控制器代碼 …

使用TIANAI-CAPTCHA進行行為驗證碼的生成和緩存的二次校驗

1.導入依賴&#xff1a;<dependency><groupId>cloud.tianai.captcha</groupId><artifactId>tianai-captcha-springboot-starter</artifactId><version>1.5.2</version> </dependency>2.在application.yml中配置驗證碼相關配置…

db.refresh()的重復使用和db.rollback()

db.refresh()在 SQLAlchemy 中&#xff0c;db.refresh() 用于從數據庫中重新加載對象的狀態&#xff0c;確保對象屬性與數據庫中的實際數據保持一致。下面詳細介紹其使用場景和作用&#xff1a;1.獲取數據庫生成的值當數據庫自動生成字段&#xff08;如自增 ID、默認值、觸發器…

《Web安全之機器學習入門》讀書筆記總結

目錄 一、案例總結 1、基礎知識 &#xff08;1&#xff09;第1章 通向智能安全的旅程 &#xff08;2&#xff09;第2章 打造機器學習工具箱 &#xff08;3&#xff09;第3章 機器學習概述 &#xff08;4&#xff09;第4章 Web安全基礎 2、安全案例 &#xff08;1&#…

github 近期熱門項目-2025.7.20

github 近期熱門項目-2025.7.20 GitHub 上近期熱門或趨勢項目的信息可以從多個來源獲取,包括 GitHub Trending 頁面、技術社區推薦、以及各大技術媒體的報道。以下是一些近期在 GitHub 上備受關注的項目類別和示例: 1. AI 與機器學習項目 隨著 AI 技術的快速發展,許多開源…

使用Python清理Excel中的空行和單元格內部空行:初學者指南

前言 作為數據處理人員或辦公室工作者,你可能經常遇到Excel文件中存在多余空行或單元格內有多余空行的問題。這些不必要的空白會影響數據的美觀性,更重要的是會給后續的數據分析、合并或處理帶來麻煩。本文將介紹一個簡單的Python腳本,幫助你高效地解決這些問題。 很多工具…

華為歐拉系統(openEuler)安裝 Docker 容器完整教程

&#x1f525; 前言&#xff1a;在國產化操作系統日益普及的當下&#xff0c;華為歐拉系統&#xff08;openEuler&#xff09;憑借其穩定性和安全性受到不少用戶青睞。但 Docker 官方暫未提供對 openEuler 的原生支持&#xff0c;不過好在 openEuler 與 CentOS 底層架構兼容&am…

數據結構--JDK17新增語法和順序表

一.yield關鍵字用于switch語句上的case代碼塊的返回值舉例&#xff1a;二.var關鍵字作用&#xff1a;當類型名字較長時可以簡化代碼。注意事項&#xff1a;1.不能使用var來聲明字段2.不能使用var來聲明方法參數3.不能使用var來聲明方法返回類型4.使用時必須初始化&#xff0c;但…

1 滲透基礎

目錄 基礎前沿 1 vulhub環境搭建 1 proxychains工具&#xff1a;編輯配置文件 2 docker docker環境搭建 配置docker的代理&#xff1a; 2 nginx編譯安裝--FPM 1 php.ini 2 php-fpm 3 nginx 4 nginx php-fpm php 1 基本角色分工 2. 請求處理全流程 步驟 1&#xff…

基于Java+SpringBoot 的榆林特色旅游網站

源碼編號&#xff1a;S678源碼名稱&#xff1a;基于SpringBoot 的榆林特色旅游網站用戶類型&#xff1a;雙角色&#xff0c;用戶、管理員數據庫表數量&#xff1a;22 張表主要技術&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven運行環境&#xff1a;Windows/Mac、JDK1…

Python設計模式深度解析:單例模式(Singleton Pattern)完全指南

Python設計模式深度解析&#xff1a;單例模式&#xff08;Singleton Pattern&#xff09;完全指南前言什么是單例模式&#xff1f;單例模式的三個關鍵要素基礎實現&#xff1a;異常控制式單例Python中的經典單例實現1. 使用 __new__ 方法實現2. 線程安全的單例實現3. 裝飾器實現…

LVS 原理詳解及部署(包含實驗案例)

一、集群和分布式簡介1.系統性能擴展方式Scale Up&#xff08;向上擴展&#xff09;&#xff1a;通過增強單臺服務器的硬件性能&#xff08;如提升 CPU、內存、存儲等&#xff09;來提高處理能力&#xff0c;適用于業務初期或對單點性能要求高的場景。這種方式簡單易行&#xf…

兩個路由器通過不同的網段互聯

一&#xff0c;實驗拓撲圖&#xff1a;二、實驗說明 &#xff1a;在兩個接口配置好兩個不同網段的的ip地址后是不能相互通信的。經過測試用ospf把兩個網段宣告進area 0 是行不通的。最后我們通過靜態路由來配置&#xff0c;遇到一個最大的問題是&#xff0c;我們的下一跳地址應…

Python趣味算法:冒泡排序——從理論到極致優化

排序算法是程序員的必修課,而冒泡排序是理解算法思維的絕佳起點。本文將深入解析冒泡排序的7種優化技巧,通過可視化演示+多維度性能分析,帶你徹底掌握這一經典算法! 看在每天堅持分享有趣知識的份上,點個關注吧(づ ̄ 3 ̄)づ 關注是我更新的動力 ̄︶ ̄? ̄︶ ̄?) 作者會…

[simdjson] document_stream | iterate_many() | batch_size | 線程加速 | 輕量handle

第七章&#xff1a;文檔流 歡迎回來 在前面的章節中&#xff0c;我們學習了如何使用解析器結合填充字符串獲取表示JSON根節點的文檔&#xff0c;并通過按需API&#xff08;On-Demand API&#xff09;遍歷值、對象和數組&#xff0c;同時使用simdjson_result進行錯誤處理。 到…

【機器學習】向量數據庫選型指南:企業內網部署場景

向量數據庫選型指南&#xff1a;企業內網部署場景一、選型背景與關鍵需求 在企業級機器學習應用中&#xff0c;特別是涉及圖片、視頻等非結構化數據的場景&#xff0c;向量數據庫已成為核心基礎設施。傳統數據庫難以高效處理高維向量的相似度檢索需求&#xff08;如圖片相似性搜…

Django母嬰商城項目實踐(八)- 數據渲染與顯示之首頁

8、數據渲染與顯示 1 概述 Django作為Web框架,需要一種很便利的方法動態地生成HTML網頁,因此有了模板這個概念。模板包含所需HTML的部分代碼以及一些特殊語法,特殊語法用于描述如何將視圖傳遞的數據動態插入HTML網頁中。 Django可以配置一個或多個模板引擎(甚至是0個,如前…

Redis常見線上問題

文章目錄 Redis常見線上問題 引言 報告背景與目的 Redis版本與環境說明 性能瓶頸問題 慢查詢分析與優化 高CPU與網絡延遲 內存管理問題 內存碎片成因與優化 BigKey與內存溢出 數據一致性與高可用問題 主從同步延遲 腦裂問題與解決方案 持久化機制問題 RDB與AOF對比 核心特性對比…