硬核解析MySQL的MVCC實現原理,面試官看了都直呼內行

来源:https://www.cnblogs.com/yidengjiagou/archive/2022/09/06/16663224.html
-Advertisement-
Play Games

MVCC全稱是Multi-Version Concurrency Control(多版本併發控制),是一種併發控制的方法,通過維護一個數據的多個版本,減少讀寫操作的衝突。 如果沒有MVCC,想要實現同一條數據的併發讀寫,還要保證數據的安全性,就需要操作數據的時候加讀鎖和寫鎖,這樣就降低了資料庫的併發... ...


1. 什麼是MVCC

MVCC全稱是Multi-Version Concurrency Control(多版本併發控制),是一種併發控制的方法,通過維護一個數據的多個版本,減少讀寫操作的衝突。

如果沒有MVCC,想要實現同一條數據的併發讀寫,還要保證數據的安全性,就需要操作數據的時候加讀鎖和寫鎖,這樣就降低了資料庫的併發性能。

有了MVCC,就相當於把同一份數據生成了多個版本,在操作的開始各生成一個快照,讀寫操作互不影響。無需加鎖,也實現數據的安全性和事務的隔離性。

事務的四大特性中隔離性就是基於MVCC實現的。

說MVCC的實現原理之前,先說一下事務的隔離級別。

2. 事務的隔離級別

說隔離級別之前,先說一下併發事務產生的問題

臟讀: 一個事務讀到其他事務未提交的數據。

不可重覆讀: 相同的查詢條件,多次查詢到的結果不一致,即讀到其他事務提交後的數據。

幻讀: 相同的查詢條件,多次查詢到的結果不一致,即讀到其他事務提交後的數據。

不可重覆讀與幻讀的區別是: 不可重覆讀是讀到了其他事務執行update、delete後的數據,而幻讀是讀到其他事務執行insert後的數據。

再說一下事務的四大隔離級別:

Read UnCommitted(讀未提交): 讀到其他事務未提交的數據,會出現臟讀、不可重覆讀、幻讀。

Read Committed(讀已提交): 讀到其他事務已提交的數據,解決了臟讀,會出現不可重覆讀、幻讀。

Repeatable Read(可重覆讀): 相同的條件,多次讀取到的結果一致。解決了臟讀、不可重覆讀,會出現幻讀。

Serializable(串列化): 所有事務串列執行,解決了臟讀、不可重覆讀、幻讀。

隔離級別 臟讀 不可重覆讀 幻讀
讀未提交
讀已提交 不會
可重覆讀 不會 不會
串列化 不會 不會 不會

MVCC只在Read CommittedRepeatable Read兩個隔離級別下起作用,因為Read UnCommitted隔離級別下,讀寫都不加鎖,Serializable隔離級別下,讀寫都加鎖,也就不需要MVCC了。

再談一下Undo log日誌。

3. Undo Log(回滾日誌)

Undo Log記錄的是邏輯日誌,也就是SQL語句。

比如:當我們執行一條insert語句時,Undo Log就記錄一條相反的delete語句。

作用:

  1. 回滾事務時,恢復到修改前的數據。

  2. 實現 MVCC

事務四大特性中原子性也是基於Undo Log實現的。

下麵開始談一下MVCC的實現原理。

4. MVCC的實現原理

4.1 當前讀和快照讀

先普及一下什麼是當前讀和快照讀。

當前讀: 讀取數據的最新版本,並對數據進行加鎖。

例如:insert、update、delete、select for update、 select lock in share mode。

快照讀: 讀取數據的歷史版本,不對數據加鎖。

例如:select

MVCC是基於Undo Log、隱藏欄位、Read View(讀視圖)實現的。

4.2 隱藏欄位

先說一下MySQL的隱藏欄位,當我們創建一張表時,InnoDB引擎會增加2個隱藏欄位。

DB_TRX_ID(最近一次提交事務的ID):修改表數據時,都會提交事務,每個事務都有一個唯一的ID,這個欄位就記錄了最近一次提交事務的ID。

DB_ROLL_PTR(上個版本的地址):修改表數據時,舊版本的數據都會被記錄到Undo Log日誌中,每個版本的數據都有一個版本地址,這個欄位記錄的就是上個版本的地址。

4.3 版本鏈

當我們第一次往用戶表插入一條記錄時,表數據和隱藏欄位的值是下麵這樣的:

insert into user (name,age) values ('一燈',1);

事務ID(DB_TRX_ID)是1,上個版本地址(DB_ROLL_PTR)是null。

image

第二次提交事務,把用戶年齡加1。

update user set age=age+1 where id=1;

事務ID變成2,上個版本地址指向Undo Log中的記錄。

image

第三次提交事務,再把用戶年齡加1。

update user set age=age+1 where id=1;

事務ID變成3,上個版本地址指向Undo Log中事務ID為2的記錄。

image

這樣表記錄和Undo Log歷史數據就組成了一個版本鏈。

4.4 Read View(讀視圖)

在事務中,執行SQL查詢,就會生成一個讀視圖,是用來保證數據的可見性,即讀到Undo Log中哪個版本的數據。

快照讀一般是讀取的歷史版本的讀視圖,當前圖會生成一個最新版本的讀視圖。

讀視圖是基於下麵幾個欄位實現的:

m_ids :當前系統中活躍的事務ID集合,即未提交的事務。

min_trx_id :m_ids中最小的ID

max_trx_id :下一個要分配的事務ID

creator_trx_id: 當前事務ID

讀視圖決定當前事務能讀到哪個版本的數據,從表記錄到Undo Log歷史數據的版本鏈,依次匹配,滿足哪個版本的匹配規則,就能讀到哪個版本的數據,一旦匹配成功就不再往下匹配。

數據可見性規則:

  1. DB_TRX_ID = creator_trx_id
    如果這個版本數據的事務ID等於當前事務ID,表示數據記錄的最後一次操作的事務就是當前事務,當前讀視圖可以讀到這個版本的數據。
  2. DB_TRX_ID < min_trx_id
    如果這個版本數據的事務ID小於所有活躍事務ID,表示這個版本的數據不再被事務使用,即事務已提交,當前讀視圖可以讀到這個版本的數據。
  3. DB_TRX_ID >= max_trx_id
    如果這個版本數據的事務ID大於等於下一個要分配的事務ID,表示有新事務更新了這個版本的數據,這種情況下,當前讀視圖不可以讀到這個版本的數據。
  4. min_trx_id <= DB_TRX_ID < max_trx_id
    如果這個版本數據的事務ID在當前系統中活躍的事務ID集合(m_ids)裡面,表示這個版本的數據被其他事務更新過,當前讀視圖不可以讀到這個版本的數據。
    如果這個版本數據的事務ID不在當前系統中活躍的事務ID集合(m_ids)裡面,表示是在其他事務提交後創建的讀視圖,當前讀視圖可以讀到這個版本的數據。

5. 不同隔離級別下可見性分析

在不同的事務隔離級別下,生成讀視圖的規則不同:

  • READ COMMITTED(讀已提交) :在事務中每一次執行快照讀時都生成一個讀視圖,每個讀視圖中四個欄位的值都是不同的。
  • REPEATABLE READ(可重覆讀):僅在事務中第一次執行快照讀時生成讀視圖,後續復用這個讀視圖。

5.1 READ COMMITTED(讀已提交)

設置MySQL隔離級別為讀已提交:

SET session TRANSACTION ISOLATION LEVEL READ COMMITTED;

image

執行兩個事務,驗證一下:

image

事務1第一次查詢時,會生成一個讀視圖,讀視圖的各個屬性如下:

屬性
m_ids 1,2
min_limit_id 1
max_limit_id 3
creator_trx_id 1

可見的版本鏈數據是:

image

符號規則 DB_TRX_ID = creator_trx_id = 1,可以看到當前版本的數據。

事務1第二次查詢時,會生成一個新的讀視圖,讀視圖的各個屬性如下:

屬性
m_ids 1
min_limit_id 1
max_limit_id 3
creator_trx_id 1

可見的版本鏈數據是:

image

符號規則 min_trx_id <= DB_TRX_ID < max_trx_id(1<=2<3),並且當前數據版本的事務ID不在當前系統中活躍的事務ID集合,可以看到當前版本的數據。

image

同一個事務內,相同的查詢條件,查詢到的數據不一致,查到了其他事務更新過的數據,也就是出現了不可重覆讀的情況。

再看一下,在可重覆讀隔離級別下,是怎麼解決這個問題的。

5.2 REPEATABLE READ(可重覆讀)

設置MySQL隔離級別為可重覆讀:

SET session TRANSACTION ISOLATION LEVEL REPEATABLE READ;

image

執行兩個事務,驗證一下:

image

事務1第一次查詢時,會生成一個讀視圖,讀視圖的各個屬性如下:

屬性
m_ids 1,2
min_limit_id 1
max_limit_id 3
creator_trx_id 1

可見的版本鏈數據是:

image

符號規則 DB_TRX_ID = creator_trx_id = 1,可以看到當前版本的數據。

事務1第二次查詢時,會復用原有的讀視圖,讀視圖的各個屬性如下:

屬性
m_ids 1,2
min_limit_id 1
max_limit_id 3
creator_trx_id 1

可見的版本鏈數據是:

image

符號規則 min_trx_id <= DB_TRX_ID < max_trx_id(1<=2<3),並且當前數據版本的事務ID在當前系統中活躍的事務ID集合,所以是不可以看到當前版本的數據。

image

由此得知,可重覆讀隔離級別下,相同的查詢條件,兩次查詢到的結果相同,也就是解決了可重覆讀的問題,是通過復用原有的讀視圖的方式解決的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 打開Visual Studio Installer 可以看到vs2022 只支持安裝4.6及以上的版本,如圖所示。那麼該如何安裝4.6以下的版本,下麵將詳細介紹。 安裝4.0~4.5系列 1、在微軟 Visual Studio SDK(https://dotnet.microsoft.com/zh- ...
  • 一:背景 前段時間在訓練營上課的時候就有朋友提到一個問題,為什麼 Windbg 附加到 C# 程式後,程式就處於中斷狀態了?它到底是如何實現的? 其實簡而言之就是線程的遠程註入,這一篇就展開說一下。 二:實現原理 1. 基本思路 WinDbg 在附加進程的時候,會註入一個線程到 C# 進程 中,註入 ...
  • zabbix自定義監控進程與日誌 zabbix自定義監控進程 基於之前的郵箱告警,部署完成後,我們在zabbix客戶端進行編譯腳本用來監控進程, 下麵是通過httpd進程來進行測試 在客戶端 [root@localhost ~]# dnf -y install httpd //下載httpd [ro ...
  • zabbix自定義監控 自定義監控進程 測試監控httpd,需要在監控端部署httpd,以方便監控 `` 配置監控腳本 #在監控端 [root@localhost ~]# dnf -y install httpd [root@localhost ~]# systemctl start httpd [ ...
  • 巴西ANATEL近日發佈了一項新的5159法案,該法案內容主要是關於行動電話使用的有線和無線電源和充電器。 法案稱為《手機用充電器合格評定技術要求及測試程式》,涵蓋了產品安全性和EMC的要求。新規將於公佈後180天,即今年10月26日起生效,該法案將取代現行的3481法案。 5159法案的新規定確實 ...
  • 1. 前言 筆者在 《從 Linux 內核角度看 IO 模型的演變》一文中曾對 Socket 文件在內核中的相關數據結構為大家做了詳盡的闡述。 又在此基礎之上介紹了針對 socket 文件的相關操作及其對應在內核中的處理流程: 並與 epoll 的工作機制進行了串聯: 通過這些內容的串聯介紹,我想大 ...
  • 前置條件 確認系統版本 win10 19041版本以及更高 查看方式:win + r 輸入winver win11 * 啟用或關閉Windows功能 win + r, 輸入 optionalfeatures,勾選適用於Linux的Windows子系統,和虛擬機平臺選項。然後重啟電腦。 官方文檔提示可 ...
  • 2022-09-06 1、為某個欄位設置別名(as關鍵字) 以“students”為例: students表的欄位有:id,name,age,gender,is_del select name as n,age as a from students; 說明:select 屬性名 as 新名稱,屬性名 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...