成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖解 | 聊聊 MyBatis 緩存

數據庫 其他數據庫
本篇分別介紹了 MyBatis 一級緩存、二級緩存、自定義緩存的原理和使用,其中還穿插了 4 道考題來驗證 MyBatis 緩存的功能。不足之處是 MyBatis 緩存源碼未分析。

你好,我是悟空。

本文主要內容如下:

圖片

一、MyBatis 緩存中的常用概念

MyBatis 緩存:它用來優化 SQL 數據庫查詢的,但是可能會產生臟數據。

SqlSession:代表和數據庫的一次會話,向用戶提供了操作數據庫的方法。

MappedStatement:代表要發往數據庫執行的指令,可以理解為是 SQL 的抽象表示。

Executor:代表用來和數據庫交互的執行器,接受 MappedStatment 作為參數。

namespace:每個 Mapper 文件只能配置一個 namespace,用來做 Mapper 文件級別的緩存共享。

映射接口:定義了一個接口,然后里面的接口方法對應要執行 SQL 的操作,具體要執行的 SQL 語句是寫在映射文件中。

映射文件:MyBatis 編寫的 XML 文件,里面有一個或多個 SQL 語句,不同的語句用來映射不同的接口方法。通常來說,每一張單表都對應著一個映射文件。

二、MyBatis 一級緩存

2.1 一級緩存原理

在一次 SqlSession 中(數據庫會話),程序執行多次查詢,且查詢條件完全相同,多次查詢之間程序沒有其他增刪改操作,則第二次及后面的查詢可以從緩存中獲取數據,避免走數據庫。

圖片

每個SqlSession中持有了Executor,每個Executor中有一個LocalCache。當用戶發起查詢時,MyBatis根據當前執行的語句生成MappedStatement,在Local Cache進行查詢,如果緩存命中的話,直接返回結果給用戶,如果緩存沒有命中的話,查詢數據庫,結果寫入Local Cache,最后返回結果給用戶。

Local Cache 其實是一個 hashmap 的結構:

private Map<Object, Object> cache = new HashMap<Object, Object>();

如下圖所示,有兩個 SqlSession,分別為 SqlSession1 和 SqlSession2,每個 SqlSession 中都有自己的緩存,緩存是 hashmap 結構,存放的鍵值對。

鍵是 SQL 語句組成的 Key :

Statement Id + Offset + Limmit + Sql + Params

值是 SQL 查詢的結果:

圖片

2.2 一級緩存配置

在 mybatis-config.xml 文件配置,name=localCacheScope,value有兩種值:SESSION 和 STATEMENT

<configuration>
<settings>
<setting name="localCacheScope" value="SESSION"/>
</settings>
<configuration>

SESSION:開啟一級緩存功能

STATEMENT:緩存只對當前執行的這一個 SQL 語句有效,也就是沒有用到一級緩存功能。

首先我們通過幾個考題來體驗下 MyBatis 一級緩存。

2.3 一級緩存考題

考題(1)只開啟了一級緩存,下面的代碼調用了三次查詢操作 getStudentById,請判斷,下列說法正確的是?

// 打開一個 SqlSession
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 根據 id=1 查詢學生信息
System.out.println(studentMapper.getStudentById(1));
// 根據 id=1 查詢學生信息
System.out.println(studentMapper.getStudentById(1));
// 根據 id=1 查詢學生信息
System.out.println(studentMapper.getStudentById(1));

答案:第一次從數據庫查詢到的數據,第二次和第二次從 MyBatis 一級緩存查詢的數據。

解答:第一次從數據庫查詢后,后續查詢走 MyBatis 一級緩存

考題(2)只開啟了一級緩存,下面代碼示例中,開啟了一個 SqlSession 會話,調用了一次查詢,然后對數據進行了更改,又調用了一次查詢,下列關于兩次查詢的說法,正確的是?

// 打開一個 SqlSession
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 根據 id=1 查詢學生信息
System.out.println(studentMapper.getStudentById(1));
// 插入了一條學生數據,改變了數據庫
System.out.println("增加了" + studentMapper.addStudent(buildStudent()) + "個學生");
// 根據 id=1 查詢學生信息
System.out.println(studentMapper.getStudentById(1));
sqlSession.close();

答案:第一次從數據庫查詢到的數據,第二次從數據庫查詢的數據

解答:第一次從數據庫查詢后,后續更新(包括增刪改)數據庫中的數據后,這條 SQL 語句的緩存失效了,后續查詢需要重新從數據庫獲取數據。

考題(3)當開啟了一級緩存,下面的代碼中,開啟了兩個 SqlSession,第一個 SqlSession 查詢了兩次學生 A 的姓名,第二次 SqlSession 更新了一次學生 A 的姓名,請判斷哪個選項符合最后的查詢結果。

SqlSession sqlSession1 = factory.openSession(true); 
SqlSession sqlSession2 = factory.openSession(true);
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class); studentMapper2.updateStudentName("B",1);
System.out.println(studentMapper.getStudentById(1));
System.out.println(studentMapper2.getStudentById(1));

答案:

A
B

解答:只開啟一級緩存的情況下,SqlSession 級別是不共享的。代碼示例中,分別創建了兩個 SqlSession,在第一個 SqlSession 中查詢學生 A 的姓名,第二個 SqlSession 中修改了學生 A 的姓名為 B,SqlSession2 更新了數據后,不會影響 SqlSession1,所以 SqlSession1 查到的數據還是 A。

2.4 MyBatis 一級緩存失效的場景

  • 不同的SqlSession對應不同的一級緩存
  • 同一個SqlSession但是查詢條件不同
  • 同一個SqlSession兩次查詢期間執行了任何一次增刪改操作
  • 同一個SqlSession兩次查詢期間手動清空了緩存

2.5 MyBatis 一級緩存總結

MyBatis一級緩存內部設計簡單,只是一個沒有容量限定的 HashMap,在緩存的功能性上有所欠缺

MyBatis的一級緩存最大范圍是SqlSession內部,有多個SqlSession或者分布式的環境下,數據庫寫操作會引起臟數據,建議設定緩存級別為Statement

一級緩存的配置中,默認是 SESSION 級別,即在一個MyBatis會話中執行的所有語句,都會共享這一個緩存。

三、MyBatis 二級緩存

3.1 MyBatis 二級緩存概述

MyBatis的二級緩存相對于一級緩存來說,實現了SqlSession之間緩存數據的共享,同時粒度更加的細,能夠到namespace級別,通過Cache接口實現類不同的組合,對Cache的可控性也更強。

MyBatis在多表查詢時,極大可能會出現臟數據,有設計上的缺陷,安全使用二級緩存的條件比較苛刻。

在分布式環境下,由于默認的MyBatis Cache實現都是基于本地的,分布式環境下必然會出現讀取到臟數據,需要使用集中式緩存將 MyBatis的Cache 接口實現,有一定的開發成本,直接使用Redis、Memcached 等分布式緩存可能成本更低,安全性也更高。

3.2 MyBatis 二級緩存原理

一級緩存最大的共享范圍就是一個 SqlSession 內部,如果多個 SqlSession 之間需要共享緩存,則需要使用到二級緩存。

開啟二級緩存后,會使用 CachingExecutor 裝飾 Executor,進入一級緩存的查詢流程前,先在CachingExecutor 進行二級緩存的查詢。

二級緩存開啟后,同一個 namespace下的所有操作語句,都影響著同一個Cache。

圖片

每個 Mapper 文件只能配置一個 namespace,用來做 Mapper 文件級別的緩存共享。

<mapper namespace="mapper.StudentMapper"></mapper>

二級緩存被同一個 namespace 下的多個 SqlSession 共享,是一個全局的變量。MyBatis 的二級緩存不適應用于映射文件中存在多表查詢的情況。

通常我們會為每個單表創建單獨的映射文件,由于MyBatis的二級緩存是基于namespace的,多表查詢語句所在的namspace無法感應到其他namespace中的語句對多表查詢中涉及的表進行的修改,引發臟數據問題。

3.3 MyBatis緩存查詢的順序

圖片

  • 先查詢二級緩存,因為二級緩存中可能會有其他程序已經查出來的數據,可以拿來直接使用
  • 如果二級緩存沒有命中,再查詢一級緩存
  • 如果一級緩存也沒有命中,則查詢數據庫
  • SqlSession關閉之后,一級緩存中的數據會寫入二級緩存。

3.4 二級緩存配置

開啟二級緩存需要在 mybatis-config.xml 中配置:

<settingname="cacheEnabled"value="true"/>

3.5 二級緩存考題

測試update操作是否會刷新該namespace下的二級緩存。

開啟了一級和二級緩存,通過三個SqlSession 查詢和更新 學生張三的姓名,判斷最后的輸出結果是什么?

SqlSession sqlSession1 = factory.openSession(true); 
SqlSession sqlSession2 = factory.openSession(true);
SqlSession sqlSession3 = factory.openSession(true);
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
StudentMapper studentMapper3 = sqlSession3.getMapper(StudentMapper.class); System.out.println("studentMapper讀取數據: " + studentMapper.getStudentById(1));
sqlSession1.commit();
System.out.println("studentMapper2讀取數據: " + studentMapper2.getStudentById(1)); studentMapper3.updateStudentName("李四",1);
sqlSession3.commit();
System.out.println("studentMapper2讀取數據: " + studentMapper2.getStudentById(1));

答案:

張三
張三
李四

解答:三個 SqlSession 是共享 MyBatis 緩存,SqlSession2 更新數據后,MyBatis 的 namespace 緩存(StudentMapper) 就失效了,SqlSession2 最后是從數據庫查詢到的數據。

四、MyBatis 自定義緩存

4.1 MyBatis 自定義緩存概述

當 MyBatis 二級緩存不能滿足要求時,可以使用自定義緩存替換。(較少使用)

自定義緩存需要實現 MyBatis 規定的接口:org.apache.ibatis.cache.Cache。這個接口里面定義了 7 個方法,我們需要自己去實現對應的緩存邏輯。

圖片

4.2 整合第三方緩存 EHCache

EHCache 和 MyBatis 已經幫我們整合好了一個自定義緩存,我們可以直接拿來用,不需要自己去實現 MyBatis 的 org.apache.ibatis.cache.Cache 接口。

添加 mybatis-ehcache 依賴包。

<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>

創建EHCache的配置文件ehcache.xml。

<?xml versinotallow="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocatinotallow="../config/ehcache.xsd">
<!-- 磁盤保存路徑 -->
<diskStore path="D:\passjava\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSecnotallow="120"
timeToLiveSecnotallow="120"
diskExpiryThreadIntervalSecnotallow="120"
memoryStoreEvictinotallow="LRU">
</defaultCache>
</ehcache>

設置二級緩存的類型,在xxxMapper.xml文件中設置二級緩存類型

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

4.3 EHCache配置文件說明

圖片

五、總結

本篇分別介紹了 MyBatis 一級緩存、二級緩存、自定義緩存的原理和使用,其中還穿插了 4 道考題來驗證 MyBatis 緩存的功能。不足之處是 MyBatis 緩存源碼未分析。

參考資料:

??https://tech.meituan.com/2018/01/19/mybatis-cache.html??

責任編輯:武曉燕 來源: 悟空聊架構
相關推薦

2020-12-28 08:03:26

多線程進程瀏覽器

2023-02-24 16:46:25

Glide緩存機制

2023-05-12 11:52:21

緩存場景性能

2020-05-27 08:05:33

MybatisMapper接口

2022-06-17 07:49:14

緩存LRU

2018-04-03 09:27:42

分布式架構系統

2021-12-09 12:22:28

MyBatis流程面試

2023-09-21 08:05:49

Mybatis插件開發

2020-02-19 19:18:02

緩存查詢速度淘汰算法

2023-06-26 08:31:59

哈希緩存系統

2016-11-28 09:00:10

瀏覽器瀏覽器緩存服務端

2025-01-02 14:50:34

MyBatis開發緩存

2024-06-12 08:36:25

2019-07-29 11:00:56

MyBatis緩存SQL

2018-07-12 15:30:03

HTTP緩存機制

2019-07-21 09:17:11

數據緩存架構

2024-12-23 06:40:00

2025-01-07 09:07:36

接口屬性路徑

2022-07-11 09:00:37

依賴配置文件Mybati

2023-04-27 08:18:10

MyBatis緩存存儲
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一二三在线视频 | 韩国主播午夜大尺度福利 | 91福利电影在线观看 | 超碰国产在线 | 中文日本在线 | 日韩精品免费视频 | 午夜免费福利影院 | 婷婷免费视频 | 欧美精品乱码久久久久久按摩 | 国产高清一区二区三区 | 日本久久综合 | 2019天天操 | 久久99国产精品 | 精品国产1区2区3区 一区二区手机在线 | 一区二区视频在线观看 | 四虎午夜剧场 | 美女在线国产 | 一区二区三区视频在线 | 成人一级视频在线观看 | 一区二区三区国产 | 国产精品性做久久久久久 | 国产精品一区一区 | 国产精品一级在线观看 | 激情欧美日韩一区二区 | 国产精品区二区三区日本 | 日韩欧美一区二区三区免费观看 | 久久久久综合 | 天天干亚洲 | 国产精品国产三级国产aⅴ中文 | 成人妇女免费播放久久久 | 欧美精品综合在线 | 久久av资源网 | 亚洲欧洲中文 | 国产一区| 国产乱码久久久久久一区二区 | 97伦理最新伦理 | 犬夜叉在线观看 | 免费观看av| 精品一区二区三区在线观看 | 国产中文在线观看 | 一级大片免费 |