【Mysql】MVCC版本機制的多并發

🌇個人主頁:平凡的小蘇
📚學習格言:命運給你一個低的起點,是想看你精彩的翻盤,而不是讓你自甘墮落,腳下的路雖然難走,但我還能走,比起向陽而生,我更想嘗試逆風翻盤
🛸Mysql專欄Mysql內功修煉基地
> 家人們更新不易,你們的👍點贊👍和?關注?真的對我真重要,各位路 過的友友麻煩多多點贊關注。 歡迎你們的私信提問,感謝你們的轉發! 關注我,關注我,關注我,你們將會看到更多的優質內容!!

在這里插入圖片描述

一、三種數據庫并發的場景

讀-讀 :不存在任何問題,也不需要并發控制

讀-寫 :有線程安全問題,可能會造成事務隔離性問題,可能遇到臟讀,幻讀,不可重復讀

寫-寫 :有線程安全問題,可能會存在更新丟失問題,比如第一類更新丟失,第二類更新丟失(后面補充)

二、讀寫并發

多版本并發控制( MVCC )是一種用來解決 讀-寫沖突 的無鎖并發控制為事務分配單向增長的事務ID,為每個修改保存一個版本,版本與事務ID關聯,讀操作只讀該事務開始前的數據庫的快照。 所以 MVCC 可以為數據庫解決以下問題:

  • 在并發讀寫數據庫時,可以做到在讀操作時不用阻塞寫操作,寫操作也不用阻塞讀操作,提高了數據庫并發讀寫的性能

  • 同時還可以解決臟讀,幻讀,不可重復讀等事務隔離問題,但不能解決更新丟失問題

2.1、三個前置知識

  • 每個事務都有自己的事務id,可以根據事務id的大小,來決定事務到來的先后順序

  • mysqld可能會面臨處理多個事務的情況,事務也有自己的生命周期,mysqld要對多個事務進行管理,先描述,在組織。事務在我看來,mysqld中一定是對應的一個或者一套結構體對象,事務也有自己的結構體

3個記錄隱藏列字段

  • DB_TRX_ID :6 byte,最近修改( 修改/插入 )事務ID,記錄創建這條記錄/最后一次修改該記錄的事務ID

  • DB_ROLL_PTR : 7 byte,回滾指針,指向這條記錄的上一個版本(簡單理解成,指向歷史版本就行,這些數據一般在 undo log 中)

  • DB_ROW_ID : 6 byte,隱含的自增ID(隱藏主鍵),如果數據表沒有主鍵, InnoDB 會自動以DB_ROW_ID 產生一個聚簇索引

補充:實際還有一個刪除flag隱藏字段, 既記錄被更新或刪除并不代表真的刪除,而是刪除flag變了

例如插入第一條數據的表結構

nameageDB_TRX_IDDB_ROLL_PTRDB_ROW_ID
張三20nullnull1

我們目前并不知道創建該記錄的事務ID,隱式主鍵,我們就默認設置成null,1。第一條記錄也沒有其他版本,我們設置回滾指針為null。

undo日志

我們這里理解undo log,簡單理解成,就是 MySQL 中的一段內存緩沖區,用來保存日志數據的就行。

模擬MVCC

現在有一個事務10,對student表中記錄進行修改(update):將name(張三)改成name(李四)。

  • 事務10,因為要修改,所以要先給該記錄加行鎖。

  • 修改前,現將改行記錄拷貝到undo log中,所以,undo log中就有了一行副本數據。(原理就是寫時拷貝)

  • 所以現在 MySQL 中有兩行同樣的記錄。現在修改原始記錄中的name,改成 ‘李四’。并且修改原始記錄的隱藏字段 DB_TRX_ID 為當前 事務10 的ID, 我們默認從 10 開始,之后遞增。而原始記錄的回滾指針 DB_ROLL_PTR 列,里面寫入undo log中副本數據的地址,從而指向副本記錄,既表示我的上一個版本就是它。

  • 事務10提交,釋放鎖。

在這里插入圖片描述

備注:此時,最新的記錄是’李四‘那條記錄。

現在又有一個事務11,對student表中記錄進行修改(update):將age(20)改成age(50)。

  • 事務11,因為也要修改,所以要先給該記錄加行鎖。(該記錄是那條?)

  • 修改前,現將改行記錄拷貝到undo log中,所以,undo log中就又有了一行副本數據。此時,新的 副本,我們采用頭插方式,插入undo log。

  • 現在修改原始記錄中的age,改成 50。并且修改原始記錄的隱藏字段 DB_TRX_ID 為當前 事務11 的ID。而原始記錄的回滾指針 DB_ROLL_PTR 列,里面寫入undo log中副本數據的地址,從而指向副本記錄,既表示我的上一個版本就是它。

  • 事務11提交,釋放鎖。

在這里插入圖片描述

這樣,我們就有了一個基于鏈表記錄的歷史版本鏈。所謂的回滾,無非就是用歷史數據,覆蓋當前數據

上面的一個一個版本,我們可以稱之為一個一個的快照。

delete場景

如果是delete呢?一樣的,別忘了,刪數據不是清空,而是設置flag為刪除即可。也可以形成版本。

insert場景

因為insert是插入,也就是之前沒有數據,那么insert也就沒有歷史版本。但是一般為了回滾操作,insert的數據也是要被放入undo log中,

如果當前事務commit了,那么這個undolog 的歷史insert記錄就可以被清空了。

select場景

select讀取,是讀取最新的版本呢?還是讀取歷史版本?

當前讀:讀取最新的記錄,就是當前讀。增刪改,都叫做當前讀,select也有可能當前讀,比如:selectlock in share mode(共享鎖), select for update
快照讀:讀取歷史版本(一般而言),就叫做快照讀。

我們可以看到,在多個事務同時刪改查的時候,都是當前讀,是要加鎖的。那同時有select過來,如果也要讀取最新版(當前讀),那么也就需要加鎖,這就是串行化

但如果是快照讀,讀取歷史版本的話,是不受加鎖限制的。也就是可以并行執行!換言之,提高了效率,即MVCC的意義所在。

結論:select是當前讀還是快照讀,是由隔離級別決定的。

那么,如何保證,不同的事務,看到不同的內容呢?也就是如何如何實現隔離級別?

MVCC機制Read View

  • Read View就是事務進行 快照讀 操作的時候生產的 讀視圖 (Read View),在該事務執行的快照讀的那一刻,會生成數據庫系統當前的一個快照,記錄并維護系統當前活躍事務的ID(當每個事務開啟時,都會被分配一個ID, 這個ID是遞增的,所以最新的事務,ID值越大)

  • Read View 在MySQL 源碼中,就是一個類,本質是用來進行可見性判斷的。 即當我們某個事務執行快照讀的時候,對該記錄創建一個 Read View 讀視圖,把它比作條件,用來判斷當前事務能夠看到哪個版本的數據,既可能是當前最新的數據,也有可能是該行記錄的 undo log 里面的某個版本的數據。

下面是 ReadView 結構

class ReadView {
// 省略...
private:
/** 高水位,大于等于這個ID的事務均不可見*/
trx_id_t m_low_limit_id
/** 低水位:小于這個ID的事務均可見 */
trx_id_t m_up_limit_id;
/** 創建該 Read View 的事務ID*/
trx_id_t m_creator_trx_id;
/** 創建視圖時的活躍事務id列表*/
ids_t m_ids;
/** 配合purge,標識該視圖不需要小于m_low_limit_no的UNDO LOG,
* 如果其他視圖也不需要,則可以刪除小于m_low_limit_no的UNDO LOG*/
trx_id_t m_low_limit_no;
/** 標記視圖是否被關閉*/
bool m_closed;
// 省略...
};m_ids; //一張列表,用來維護Read View生成時刻,系統正活躍的事務ID
up_limit_id; //記錄m_ids列表中事務ID最小的ID(沒有寫錯)
low_limit_id; //ReadView生成時刻系統尚未分配的下一個事務ID,也就是目前已出現過的事務ID的
//最大值+1(也沒有寫錯)
creator_trx_id //創建該ReadView的事務ID

在這里插入圖片描述

注意:read view是事務可見性的一個類,不是事務創建出來,就會有read view,而是當這個事務(已經存在),首次進行快照讀的時候,mysql 形成read view!

Read View實驗

假設當前有條記錄:

nameageDB_TRX_IDDB_ROW_IDDB_ROLL_PTR
王五23null1null

事務操作:
在這里插入圖片描述

  • 事務4:修改name(王五) 變成name(李六)

  • 當 事務2 對某行數據執行了 快照讀 ,數據庫為該行數據生成一個 Read View 讀視圖

//事務2的 Read View
m_ids; // 1,3
up_limit_id; // 1
low_limit_id; // 4 + 1 = 5,原因:ReadView生成時刻,系統尚未分配的下一個事務ID
creator_trx_id // 2 快照讀id
  • 只有事務4修改過該行記錄,并在事務2執行快照讀前,就提交了事務

  • 我們的事務2在快照讀該行記錄的時候,就會拿該行記錄的 DB_TRX_ID 去跟up_limit_id,low_limit_id和活躍事務ID列表(trx_list) 進行比較,判斷當前事務2能看到該記錄的版本。

//事務2的 Read View
m_ids; // 1,3
up_limit_id; // 1
low_limit_id; // 4 + 1 = 5,原因:ReadView生成時刻,系統尚未分配的下一個事務ID
creator_trx_id // 2
//事務4提交的記錄對應的事務ID
DB_TRX_ID=4
//比較步驟
DB_TRX_ID(4)< up_limit_id(1) ? 不小于,下一步
DB_TRX_ID(4)>= low_limit_id(5) ? 不大于,下一步
m_ids.contains(DB_TRX_ID) ? 不包含,說明,事務4不在當前的活躍事務中。

結論:

故,事務4的更改,應該看到。所以事務2能讀到的最新數據記錄是事務4所提交的版本,而事務4提交的版本也是全局角度上最新的版本

RR與RC的本質區別

  • 正是Read View生成時機的不同,從而造成RC,RR級別下快照讀的結果的不同

  • 在RR級別下的某個事務的對某條記錄的第一次快照讀會創建一個快照及Read View,

    將當前系統活躍的其他事務記錄起來

  • 此后在調用快照讀的時候,還是使用的是同一個Read View,所以只要當前事務在其他事務提交更

    新之前使用過快照讀,那么之后的快照讀使用的都是同一個Read View,所以對之后的修改不可見

  • 即RR級別下,快照讀生成Read View時,Read View會記錄此時所有其他活動事務的快照,這些事務的修改對于當前事務都是不可見的。而早于Read View創建的事務所做的修改均是可見

  • 而在RC級別下的,事務中,每次快照讀都會新生成一個快照和Read View, 這就是我們在RC級別下 的事務中可以看到別的事務提交的更新的原因

  • 總之在RC隔離級別下,是每個快照讀都會生成并獲取最新的Read View;而在RR隔離級別下,則是

    同一個事務中的第一個快照讀才會創建Read View, 之后的快照讀獲取的都是同一個Read View。正是RC每次快照讀,都會形成Read View,所以,RC才會有不可重復讀問題。

測試:當前讀和快照讀在RR級別下的區別

-- 設置RR模式下測試
mysql> set global transaction isolation level REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)
-- 重啟終端
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
-- 依舊用之前的表
create table if not exists account(
id int primary key,
name varchar(50) not null default '',
blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
-- 插入一條記錄,用來測試
mysql> insert into user (id, age, name) values (1, 15,'黃蓉');
Query OK, 1 row affected (0.00 sec)

用例一
在這里插入圖片描述

用例二
在這里插入圖片描述

  • 用例1與用例2:唯一區別僅僅是 表1 的事務B在事務A修改age前 快照讀 過一次age數據

  • 而 表2 的事務B在事務A修改age前沒有進行過快照讀。

結論

  • 事務中快照讀的結果是非常依賴該事務首次出現快照讀的地方,

    即某個事務中首次出現快照讀,決定該事務后續快照讀結果的能力

  • delete同樣如此

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

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

相關文章

PostgreSQL空值的判斷

PostgreSQL空值的判斷 空值判斷非空判斷總結 空值判斷 -- 查詢為空的 is null,sql簡寫isnull select * from employees where manager_id isnull;select * from employees where manager_id is null;非空判斷 -- 查詢不為空的 is not null;sql簡寫notnull select * from empl…

Java【數據結構】二分查找

&#x1f31e; 題目&#xff1a; &#x1f30f;在有序數組A中&#xff0c;查找目標值target &#x1f30f;如果找到返回索引 &#x1f30f;如果找不到返回-1 算法描述解釋前提給定一個內含n個元素的有序數組A&#xff0c;滿足A0<A1<A2<<An-1,一個待查值target1設…

mysql 8.0安裝

操作系統&#xff1a;22.04.1-Ubuntu apt 安裝命令 sudo apt install mysql-client-core-8.0 sudo apt install mysql-server-8.0終端輸入 mysql 可以直接免密登錄 如果此時提示需要密碼&#xff0c;則可以進入配置文件&#xff0c;設置免密登錄 sudo vim /etc/mysql/mysq…

【探索Linux】—— 強大的命令行工具 P.5(yum工具、git 命令行提交代碼)

閱讀導航 前言一、軟件包管理器 yum1.yum的概念yum的基本指令使用例子 二、git 命令行提交代碼總結溫馨提示 前言 前面我們講了C語言的基礎知識&#xff0c;也了解了一些數據結構&#xff0c;并且講了有關C的一些知識&#xff0c;也學習了一些Linux的基本操作&#xff0c;也了…

第3章 CPU微架構

3.1 指令集架構 指令集ISA是軟件用來與硬件通信的詞匯集合&#xff0c;定義了軟件和硬件之間的通信協議。Intel x86、ARM v8、RISC-V是當今廣泛使用指令集架構的實例。ISA開發者通常要確保符合規范的軟件或固件能在使用該規范構建的任何處理器上執行。廣泛部署的ISA組織通常還…

20W IP網絡吸頂喇叭 POE供電吸頂喇叭

SV-29852T 20W IP網絡吸頂喇叭產品簡介 產品用途&#xff1a; ◆室內豪華型吸頂喇叭一體化網絡音頻解碼揚聲器&#xff0c;用于廣播分區音頻解碼、聲音還原作用 ◆應用場地如火車站、地鐵、教堂、工廠、倉庫、公園停車場等&#xff1b;室內使用效果均佳。 產品特點&#xff…

vue-router中的一些 API

在Vue.js的vue-router中&#xff0c;一些重要api 1、RouterHistory&#xff1a;這是 vue-router 提供的路由歷史記錄對象。它可以跟蹤當前頁面的路由歷史&#xff0c;并提供一些方法和屬性來管理導航和歷史記錄。在 vue-router 中&#xff0c;有兩種類型的路由歷史記錄對象&…

pytorch_lightning報錯 You requested gpu: [1],But your machine only has: [0]

pytorch_lightning報錯 You requested gpu: [1]&#xff0c;But your machine only has: [0] 問題及分析 報錯圖片如下&#xff1a; 分析 gpu:[1]指代的gpu的標號&#xff0c;如果筆記本中只包含一個GPU&#xff0c;一般序號為[0].所以無法找到程序指定的GPU。 解決方法 …

機器學習之邏輯回歸

import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression # 獲得數據 names[Sample code number,Clump Thickness,Uniformity…

編程語言學習筆記-架構師和工程師的區別,PHP架構師之路

&#x1f3c6;作者簡介&#xff0c;黑夜開發者&#xff0c;全棧領域新星創作者?&#xff0c;CSDN博客專家&#xff0c;阿里云社區專家博主&#xff0c;2023年6月CSDN上海賽道top4。 &#x1f3c6;數年電商行業從業經驗&#xff0c;歷任核心研發工程師&#xff0c;項目技術負責…

Egg.js構建一個stream流式接口服務

經常需要用到 stream 流式接口服務,比如&#xff1a;大文件下載、日志實時輸出等等。本文將介紹如何使用Egg.js構建一個 stream 流式接口服務。 一、準備工作 目錄結構&#xff1a; app//controllerindex.jstest.txttest.shindex.js 控制器test.txt 測試文件&#xff0c;最好…

5G+AI數字化智能工廠建設解決方案PPT

導讀&#xff1a;原文《5GAI數字化智能工廠建設解決方案》&#xff08;獲取來源見文尾&#xff09;&#xff0c;本文精選其中精華及架構部分&#xff0c;邏輯清晰、內容完整&#xff0c;為快速形成售前方案提供參考。數字化智能工廠定義 智能基礎架構協同框架 - 端、邊、云、網…

激光雷達 01 線數

一、線數 對于 360 旋轉式和一維轉鏡式架構的激光雷達來說&#xff0c;有幾組激光收發模塊&#xff0c;垂直方向上就有幾條線&#xff0c;被稱為線數。這種情況下&#xff0c;線數就等同于激光雷達內部激光器的數量[參考]。 通俗來講&#xff0c;線數越高&#xff0c;激光器的…

npm run xxx 的時候發生了什么?(以npm run dev舉例說明)

文章目錄 一、去package.json尋找scripts對應的命令二、去node_modules尋找vue-cli-service三、從package-lock.json獲取.bin的軟鏈接1. bin目錄下的那些軟連接存在于項目最外層的package-lock.json文件中。2.vue-cli-service文件的作用3.npm install 的作用 總結 一、去packag…

Google API實戰與操作

Google api實戰與操作 一. Google API 權限配置二. 操作API2.1 引入依賴2.2 導入代碼 Google官網 實現一套用java程序控制GoogleAPI實現自動生成監控日報等功能,具體能操作Gsheet及document 一. Google API 權限配置 打開上面官網,新建項目 啟用API 搜索sheet及document …

【山河送書第七期】:《強化學習:原理與Python實戰》揭秘大模型核心技術RLHF!

《強化學習&#xff1a;原理與Python實戰》揭秘大模型核心技術RLHF&#xff01; 一圖書簡介二RLHF是什么&#xff1f;三RLHF適用于哪些任務&#xff1f;四RLHF和其他構造獎勵模型的方法相比有何優劣&#xff1f;五什么樣的人類反饋才是好反饋&#xff1f;六如何減小人類反饋帶來…

LVGL圖層的介紹

一.UI界面顯示的圖層 在lvgl開發的過程中&#xff0c;UI界面的顯示都是位于lv_sct_act()圖層 二.彈窗顯示 lvgl開發過程中&#xff0c;有些窗口有可能在任何時候顯示&#xff0c;比如錯誤信息彈窗&#xff0c;外部觸發的一些中斷。 這個時候&#xff0c;這些窗口不能建立在lv_s…

web前端開發基礎入門html5+css3+js學習筆記(一)

目錄 1.第一個前端程序2.前端工具的選擇與安裝3.VSCode開發者工具快捷鍵4.HTML5簡介與基礎骨架4.1 HTML5的DOCTYPE聲明4.2 HTML5基本骨架4.2.1 html標簽4.2.2 head標簽4.2.3 body標簽4.2.4 title標簽4.2.5 meta標簽 5.標簽之標題5.1 快捷鍵5.1 標題標簽位置擺放 6.標簽之段落、…

LeetCode每日一題——2682. 找出轉圈游戲輸家

n 個朋友在玩游戲。這些朋友坐成一個圈&#xff0c;按 順時針方向 從 1 到 n 編號。從第 i 個朋友的位置開始順時針移動 1 步會到達第 (i 1) 個朋友的位置&#xff08;1 < i < n&#xff09;&#xff0c;而從第 n 個朋友的位置開始順時針移動 1 步會回到第 1 個朋友的位…

leetcode 377. 組合總和 Ⅳ

2023.8.17 本題屬于完全背包問題&#xff0c;乍一看和昨天那題 零錢兌換II 類似&#xff0c;但細看題目發現&#xff1a;今天這題是排列問題&#xff0c;而“零錢兌換II”是組合問題。排列問題強調順序&#xff0c;而組合順序不強調順序。 這里先說個結論&#xff1a;先遍歷物品…