MySQL的可重復讀隔離級別實現原理分析

MySQL 的 可重復讀(Repeatable Read, RR) 隔離級別主要通過 多版本并發控制(Multi-Version Concurrency Control, MVCC)鎖機制(特別是間隙鎖) 來實現的。其核心目標是:在一個事務內,無論讀取多少次相同的行,看到的數據都是一致的(即第一次讀取時建立的“快照”),并且防止了“不可重復讀”問題(同一個事務內兩次讀取同一行得到不同值)。同時,在 InnoDB 的 RR 級別下,還通過間隙鎖機制(Next-Key Locks)極大地防止了“幻讀”問題(同一個事務內兩次范圍查詢得到不同的行集)。

以下是 RR 隔離級別實現的核心機制:

1. 多版本并發控制 (MVCC) - 實現快照讀 (Snapshot Read)

MVCC 是 RR 級別實現“可重復讀”特性的基石。

  • 隱式字段: InnoDB 在每個聚簇索引記錄(數據行)中隱藏了 3 個關鍵字段:
    • DB_TRX_ID (6 Bytes):記錄創建/最后修改該行的事務ID。 當一個事務開始修改某行時,會把自己的事務 ID 寫入這個字段。
    • DB_ROLL_PTR (7 Bytes):指向該行在 undo log 中的回滾段指針。 這個指針指向該行之前版本(舊版本)在 undo log 中的位置,形成一個版本鏈。
    • DB_ROW_ID (6 Bytes):單調遞增的行 ID(如果表沒有定義主鍵,InnoDB 會自動生成這個作為聚簇索引)。
  • Undo Log (回滾日志): 當事務修改數據時:
    • 會先將數據行的舊版本復制到 undo log 中。
    • 然后修改數據行(更新 DB_TRX_ID 為當前事務 ID,更新 DB_ROLL_PTR 指向剛寫入 undo log 的舊版本記錄)。
    • 這樣,每個被修改的行都通過 DB_ROLL_PTR 鏈接成一個歷史版本鏈(鏈表)。
  • ReadView (一致性視圖): 這是 MVCC 的關鍵數據結構,決定了事務能看到哪些版本的數據。當事務執行第一個 SELECT 語句(或顯式開啟只讀事務)時,InnoDB 會為該事務生成一個 ReadView。一個 ReadView 主要包含:
    • m_ids: 生成 ReadView 時,系統中活躍(未提交)的事務 ID 列表
    • min_trx_id: m_ids 中的最小值。
    • max_trx_id: 生成 ReadView 時,系統應該分配給下一個新事務的 ID(即當前最大事務 ID + 1)。
    • creator_trx_id: 創建該 ReadView 的當前事務自己的 ID(只讀事務為 0)。
  • 可見性規則: 當事務需要讀取一行時,它沿著該行的版本鏈(通過 DB_ROLL_PTR 回溯)查找第一個滿足以下條件的版本:
    1. 版本對應的 DB_TRX_ID < min_trx_id:該版本是在 ReadView 創建之前就已提交的事務修改的。可見
    2. 版本對應的 DB_TRX_IDm_ids 中:該版本是由 ReadView 創建時還活躍(未提交) 的事務修改的。不可見。繼續查找更舊的版本。
    3. 版本對應的 DB_TRX_ID >= max_trx_id:該版本是由 ReadView 創建之后才開啟的事務修改的。不可見。繼續查找更舊的版本。
    4. 版本對應的 DB_TRX_ID = creator_trx_id:該版本是由當前事務自身修改的。可見
    • 如果找到鏈頭(最初的版本)仍不可見,則認為該行對該事務不可見(如同不存在)。
  • RR 級別的關鍵點:
    • 在 RR 級別下,一個事務只在第一次執行 SELECT 時生成一個 ReadView
    • 后續在該事務內的所有 普通 SELECT 語句(快照讀)復用這個最初的 ReadView
    • 因此,無論之后其他事務如何修改、提交或回滾,該事務看到的數據始終是第一次 SELECT 時那個“快照”版本的數據。這就保證了“可重復讀”。

2. 鎖機制 (Locking) - 處理當前讀 (Current Read) 和防止幻讀

MVCC 主要解決了快照讀(普通 SELECT 的可重復讀問題。但對于當前讀(如 SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, DELETE, INSERT,以及需要防止幻讀,就需要用到鎖機制,特別是 Next-Key Locks

  • 行鎖 (Record Locks): 鎖定索引記錄本身。
  • 間隙鎖 (Gap Locks): 鎖定索引記錄之間的間隙(一個開區間),防止其他事務在這個間隙中插入新記錄。
  • 臨鍵鎖 (Next-Key Locks): 行鎖 + 間隙鎖的組合。鎖定索引記錄本身以及該記錄之前的間隙(一個左開右閉區間)。這是 InnoDB 在 RR 級別下默認使用的鎖類型
  • RR 級別下如何防止幻讀:
    • 當一個事務執行當前讀(例如 SELECT * FROM t WHERE id > 100 FOR UPDATE)時:
      1. InnoDB 不僅會鎖住所有滿足條件 id > 100現有行(行鎖)。
      2. 還會在這些現有行的索引記錄范圍之后(以及可能的間隙之間)加上間隙鎖 (Gap Locks)臨鍵鎖 (Next-Key Locks)
    • 例如,如果現有 id 是 101, 105, 110。那么 id > 100 的查詢可能會鎖定:
      • 現有行:101, 105, 110(行鎖)
      • 間隙:(100, 101), (101, 105), (105, 110)(間隙鎖)
      • 以及最大值之后的間隙:(110, +∞)(間隙鎖)
    • 這些間隙鎖會阻止其他事務在這些被鎖定的間隙中插入任何新的記錄(例如插入 id=102, 106, 115 等)。
    • 因此,在該事務提交之前,其他事務無法插入滿足其查詢條件(id > 100)的新行。當該事務再次執行相同的范圍查詢時,就不會看到新插入的行(幻行),從而防止了幻讀。
  • 為什么 RR 級別能“極大防止”而非“絕對防止”幻讀?
    • 快照讀 (SELECT): 基于 MVCC 的 ReadView,它看到的是固定快照,本身就不會看到其他事務新提交的數據(包括幻行)。所以快照讀天然不會發生幻讀。
    • 當前讀 (SELECT ... FOR UPDATE等): 通過 Next-Key Locks 鎖住索引記錄和間隙,阻止了其他事務在鎖定范圍內插入新行,從而防止了當前讀的幻讀。
    • “極大防止”的細微點: 如果一個事務 T1 只使用快照讀 (SELECT),它看不到其他事務插入的幻行(因為 MVCC)。但是,如果 T1 之后在同一個事務內執行了一個寫操作(如 UPDATEDELETE),而這個寫操作恰好影響到了其他事務新插入并提交的行(這些行對 T1 的快照讀是不可見的),那么 T1 的寫操作會“看到”這些新行(寫操作需要當前讀并可能加鎖)。如果這個寫操作修改了這些新行,那么 T1 后續的讀操作(即使是快照讀)再讀取這些被自己修改的行時,就會看到它們了。這種情況理論上構成了一種特殊的幻讀現象(寫操作發現了之前讀操作沒看到的行)。不過這種情況相對罕見,且很多業務場景下可以接受或規避。因此,通常說 InnoDB 的 RR 級別通過 Next-Key Locks “極大防止”了幻讀。

總結 MySQL RR 隔離級別的實現

  1. MVCC (核心):
    • 利用隱藏字段 (DB_TRX_ID, DB_ROLL_PTR) 和 Undo Log 構建行數據的歷史版本鏈。
    • 事務在第一次執行快照讀 (SELECT) 時生成一個 ReadView
    • 所有后續的快照讀都復用這個 ReadView,通過版本鏈的可見性規則訪問歷史快照數據,保證可重復讀
  2. Next-Key Locks (關鍵補充):
    • 默認使用臨鍵鎖(行鎖 + 間隙鎖)。
    • 當前讀 (SELECT ... FOR UPDATE/LOCK IN SHARE MODE, UPDATE, DELETE, INSERT) 時鎖定索引記錄及其前后的間隙。
    • 阻止其他事務在鎖定范圍內插入新記錄,從而極大防止了幻讀的發生。
  3. Undo Log 的清理:
    • 不再被任何活動事務的 ReadView 引用的舊版本數據(在 Undo Log 中)會被 Purge 線程清理掉。

因此,InnoDB 通過巧妙地結合 MVCC 的快照機制(處理讀)Next-Key Locks 的鎖定機制(處理寫和范圍控制),高效且強有力地實現了可重復讀(RR)隔離級別的語義要求。

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

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

相關文章

利用Java自定義格式,循環導出數據、圖片到excel

利用Java自定義格式&#xff0c;循環導出數據、圖片到excel1、自定義格式循環導出數據1.1.設置格式1.1.1、居中樣式1.1.2、應用樣式到合并區域1.1.3、合并單元格1.1.4、設置列寬1.2、寫入數據1.2.1、創建標簽頭部1.2.2、寫入標簽內容2、自定義格式循環導出圖片2.1、設置格式并插…

SAP學習筆記 - 開發45 - RAP開發 Managed App New Service Definition,Metadata Extension

上一章講了在 Data Model View ( CDS View for BO Structure )基礎上創建 Projection View ( CDS View for BO Projection )。 SAP學習筆記 - 開發44 - RAP開發 Managed App 建 Projection View&#xff0c;Provider Contract&#xff0c;用 redirected to 設定父子關系-CSDN博…

React強大且靈活hooks庫——ahooks入門實踐之高級類hook(advanced)詳解

什么是 ahooks&#xff1f; ahooks 是一個 React Hooks 庫&#xff0c;提供了大量實用的自定義 hooks&#xff0c;幫助開發者更高效地構建 React 應用。其中高級類 hooks 是 ahooks 的一個重要分類&#xff0c;專門用于處理一些高級場景&#xff0c;如受控值、事件發射器、性能…

計算機網絡——數據鏈路層(25王道最新版)

數據鏈路層前言數據鏈路層的功能封裝成幀&#xff08;組幀&#xff09;字符計數法字節填充法零比特填充法違規編碼法小節差錯控制檢錯編碼奇偶校驗碼CRC校驗碼&#xff08;循環冗余校驗碼&#xff09;基本思想如何構造如何檢錯糾錯糾錯編碼海明校驗碼設計思路求解步驟&#xff…

【PTA數據結構 | C語言版】字符串替換算法

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 請編寫程序&#xff0c;將給定主串 s 中的子串 sub_s 替換成另一個給定字符串 t&#xff0c;再輸出替換后的主串 s。 輸入格式&#xff1a; 輸入給出 3 個非空字符串&#xff0c;依次為&#xff1a…

事物生效,訂單類內部更新訂單

代碼如下以下代碼1不生效&#xff0c;2生效解決方案1&#xff0c;外層方法加注解&#xff0c;內層不加2&#xff0c;不要拆分方法&#xff0c;把更新訂單操作放在帶事物的大方法中3&#xff0c;拆方法&#xff08;內部&#xff09;&#xff0c;注入自己&#xff0c;用代理對象調…

非對稱加密:RSA

文章目錄 非對稱加密:RSA 1、RSA 加解密 2、RSA 生成密鑰對(公鑰、私鑰)、加解密 參考資料 非對稱加密:RSA 1、RSA 加解密 <!-- RSA --><!-- 引入jsencrypt庫 --><script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js&q…

MongoDB 數據庫 啟用訪問控制

0. 最近服務器安裝了 MongoDB 被勒索了 測試服務器安裝了 MongoDB 等&#xff0c;開放了 27017 對所有 ip。 哈哈哈哈哈哈&#xff0c;問就是有點犯懶&#xff0c;之前都是只允許自己的 ip。 好家伙&#xff0c;然后沒過幾個小時&#xff0c;數據庫集合被清空&#xff0c;只留…

【Unity Sprite屬性拓展】

Unity Inspector 精靈圖預覽為 Unity 中的 Sprite 類型屬性提供了??增強版的 Inspector 顯示??&#xff0c;在保留標準精靈選擇功能的基礎上&#xff0c;添加了大型預覽圖和精靈名稱顯示功能代碼 using UnityEngine; using UnityEditor;// 1?? 告訴 Unity&#xff1a;所有…

細菌實驗入門:濃度測定與菌種鑒定技術詳解

在微生物實驗中&#xff0c;細菌濃度的精準測定和菌種的準確鑒定是兩項基礎且核心的操作。本文將詳細介紹相關技術的原理、操作步驟及注意事項&#xff0c;為新手提供系統性指導。一、細菌濃度測定方法1. 光密度法&#xff08;OD600&#xff09;&#xff1a;快速定量的首選原理…

GaussDB 數據庫架構師修煉(一)數據庫容量規劃

1、容量規劃的定義GaussDB容量規劃是指根據客戶業務系統的負載需求或歷史運行數據&#xff0c;進行合理規劃GaussDB的計算、存儲和網絡資源配置&#xff0c;以滿足業務系統正常使用和未來若干年負載增長訴求的過程。2、容量規劃活動主要步驟需求收集調研生產系統的業務特征&…

hashMap原理(一)

概念HashMap是java中一種非常常用的基于哈希表的數據結構&#xff0c;允許o(1)的時間復雜度進行元素插入&#xff0c;查找&#xff0c;和刪除。它通過”鍵-值“ 對的方式存儲數據。總的來說&#xff1a;HashMap的底層原理&#xff1a;數組鏈表紅黑樹&#xff08;jdk1.8之后還涉…

Ubuntu24 輔助系統-屏幕鍵盤的back按鍵在網頁文本框刪除不正常的問題解決方法

Ubuntu24 輔助系統-屏幕鍵盤的back按鍵異常 問題描述ubuntu24這個屏幕鍵盤&#xff0c;只有在網頁的搜索框或者文本框&#xff0c;比如百度首頁的搜索框&#xff0c;留言的文本框&#xff0c;才會出現點擊back按鈕的時候&#xff0c;出現了先選中當前這個字符&#xff0c;刪除此…

自然語言指令驅動的工業機器人協同學習系統:大語言模型如何重塑智能體協作范式

重磅推薦專欄: 《大模型AIGC》 《課程大綱》 《知識星球》 本專欄致力于探索和討論當今最前沿的技術趨勢和應用領域,包括但不限于ChatGPT和Stable Diffusion等。我們將深入研究大型模型的開發和應用,以及與之相關的人工智能生成內容(AIGC)技術。通過深入的技術解析和實踐經…

web:js的switch語句

在js中,switch語句是一種用于根據不同的條件執行不同代碼塊的控制流語句。它類似于多個if...else if...else語句,但結構更清晰,特別是在有多個條件分支的情況下。 基本語法 switch (expression) {case value1:// 當expression的值等于value1時執行這里的代碼break;case va…

為何說分布式 AI 推理已成為下一代計算方式

2024 年&#xff0c;我們見證了人工智能創新的空前爆發。AI 的快速發展令很多人驚嘆&#xff0c;為了訓練更先進的大語言模型&#xff08;LLM&#xff09;&#xff0c;科技巨頭爭相獲取強大的 GPU。如今&#xff0c;AI 正在無縫融入我們世界的每個角落。在眾多新興 AI 公司、模…

阿里云 RabbitMQ 可觀測性最佳實踐

阿里云 RabbitMQ 阿里云 RabbitMQ 是一款高性能、高可靠的消息中間件&#xff0c;支持多種消息協議和豐富的功能特性。它提供消息隊列功能&#xff0c;能夠實現應用間的消息解耦和異步通信&#xff0c;提升系統擴展性和穩定性。其支持多種消息持久化策略&#xff0c;確保消息不…

vue-router 導航式編程 參數的設置

主要是想記錄一下this.$router.push、replace、go等方法的參數如何設置。字符串路徑router.push(/home)直接使用字符串&#xff08;或模板字符串&#xff09;路徑&#xff0c;可跳轉到相應的URL路徑。對象式路徑路徑也可以是一個對象&#xff0c;對象里以key:value的形式表示UR…

Swift實現股票圖:從基礎到高級

目錄一、核心實現方案1. 原生方案&#xff1a;使用 Core Graphics 繪制2. 使用第三方庫&#xff1a;Charts3. 跨平臺方案&#xff1a;使用 SwiftUI Canvas二、技術指標實現1. 移動平均線 (MA)2. 布林帶 (Bollinger Bands)3. MACD (Moving Average Convergence Divergence)三、…

【unitrix】 6.4 數特征(number.rs)

一、源碼 這段代碼定義了一個名為Number的trait&#xff08;特質&#xff09;以及它的實現。 use crate::sealed::Sealed; use crate::number::{V, BaseNumber, TNumber};/// 數值的統一標記特質 /// 可以是編譯時類型化數字(TNumber)或運行時變量(V<T>) pub trait Numbe…