事務隔離:從鎖實現到MVCC實現

文章目錄

  • 事務隔離:從鎖實現到MVCC實現
    • 事務
      • 四大特性
      • 事務隔離級別
    • 鎖實現
      • 概念
      • 實現事務隔離
    • MVCC實現
      • 當前讀與快照讀
      • 實現事務隔離
      • Read View
    • 總結

事務隔離:從鎖實現到MVCC實現

面試的時候被面試官問到:你這個項目為什么使用了可重復讀而不選擇讀已提交事務隔離級別。思考了一會發現我對事務、鎖、事務隔離級別的理解還是有所欠缺,今天來整理一下。

本文的梳理都基于下面這張簡單的表。

在這里插入圖片描述

建表語句:

CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,  -- 用戶ID,自增主鍵username VARCHAR(50) NOT NULL,      -- 用戶名,最多50字符,不能為空age INT,                            -- 年齡created_at DATETIME DEFAULT CURRENT_TIMESTAMP  -- 創建時間,默認當前時間
);

事務

事務就是數據庫中的一系列操作組成的一個整體,我們在實際業務中,需要這一系列操作必須全部執行,不能有些操作執行了,有些操作執行失敗了。

例如,小紅向小明轉賬了500元,我們需要扣減小紅500元的余額,增加小明500元的余額。

UPDATE users
SET balance = balance - 500
WHERE username = '小紅';UPDATE users
SET balance = balance + 500
WHERE username = '小明';

如果不加事務控制,這兩條語句可能會出現第一條執行了,第二條未執行的操作,就會導致500元不翼而飛了。

使用BEGIN開啟一個事務,使用COMMIT提交一個事務。

START TRANSACTION;UPDATE users
SET balance = balance - 500
WHERE username = '小紅';UPDATE users
SET balance = balance + 500
WHERE username = '小明';COMMIT;

對于單條sql語句,數據庫會自動將其看成事務執行,叫隱式事務。

四大特性

事務的四大特性:

  • A:Atomicity,原子性,將所有SQL作為原子工作單元執行,要么全部執行,要么全部不執行;
  • C:Consistency,一致性,事務完成后,所有數據的狀態都是一致的,即A賬戶只要減去了100,B賬戶則必定加上了100;
  • I:Isolation,隔離性,如果有多個事務并發執行,每個事務作出的修改必須與其他事務隔離;
  • D:Durability,持久性,即事務完成后,對數據庫數據的修改被持久化存儲。

我們所使用的鎖、MVCC、日志等一系列機制其實都是為了保證事務的者四大特性,使得事務在實際業務中使用起來不會出錯。

事務隔離級別

事務之間有四個隔離級別,分別是讀未提交,讀已提交(解決臟讀),可重復讀(解決不可重復讀),串行化(解決幻讀)。

鎖實現

鎖常用于解決并發請求導致的一系列問題。數據庫鎖也是用來處理當同時有多個事務或者請求來并發地訪問數據庫時,可能會出現的問題。

概念

數據庫鎖主要分為兩種類型:

共享鎖(Shared Lock): 也就是讀鎖,讀鎖和讀鎖不會互斥,讀鎖和寫鎖之間互斥。

排他鎖(Exclusive Lock): 也就是寫鎖,寫鎖和任何讀鎖和寫鎖都是互斥的。

數據庫中具體的鎖:

由于本文只涉及到行鎖,所以這里只簡單介紹一下行鎖。

行鎖鎖定數據庫中的某一條記錄,單個行。數據庫不同行直接可以同時進行訪問,因此提高了并發性。

共享行級鎖:多個事務可以同時獲取共享鎖,用于讀取行數據。

排他行級鎖:只允許一個事務持有排他鎖,用于修改行數據。

實現事務隔離

接下來我們梳理一下如何用鎖來實現事務隔離級別。

首先我們要知道只依靠加鎖來實現事務隔離會帶來性能降低的問題,但是了解一下會對我們更好地去理解MVCC有幫助。

**一級封鎖協議:**事務在修改一條記錄之前必須先對它添加寫鎖,直到事務(提交或者回滾)結束才釋放。

不能解決臟讀問題,因為當事務T1修改記錄,添加了寫鎖的時候,其它事務的讀是不加鎖的,依舊可以讀到數據。

二級封鎖協議: 一級封鎖協議的規則+事務在讀取記錄之前必須先對它加讀鎖,讀完后就可以釋放鎖。

可以解決臟讀問題,但是不能解決不可重復讀問題,因為讀鎖在讀完就釋放了,在到下一次讀的這中間的間隙可能就會出現別的事務將數據修改了。

三級封鎖協議: 一級封鎖協議的規則+務在讀取記錄之前必須先對它加讀鎖,但是事務結束才釋放。

可以解決臟讀問題,可以解決不可重復讀問題。

鎖協議事務隔離級別
一級封鎖協議Read Uncommitted(讀未提交)
二級封鎖協議Read Committed(讀已提交)
三級封鎖協議Repeatable Read(可重復讀)
表鎖Serializable (可串行化)

MVCC實現

可以看到上面我們只使用了鎖機制來實現了事務隔離,接下來介紹一種無鎖化的、性能更高的實現事務隔離的方法,MVCC(Multi-Version Concurrency Control),即多版本并發控制。

當前讀與快照讀

在了解MVCC實現事務隔離之前,我們先了解一下當前讀和快照讀。

當前讀: Mysql使用鎖來實現當前讀,共享鎖+排他鎖+next-key lock(間隙鎖)實現。

下面這些語法都是當前讀:

語法
SELECT … LOCK IN SHARE MODE
SELECT … FOR UPDATE
UPDATE
DELETE
INSERT

select語句加上LOCK IN SHARE MODE就是加上共享鎖進行讀,加上FOR UPDATE就是加上排他鎖進行讀。

快照讀: 快照讀是在讀取數據的時候讀取一致性視圖中的數據,Mysql使用MVCC來實現快照讀。

具體而言,每個事務在開始時會創建一個一致性視圖(Consistent View),該視圖反映了事務開始時刻數據庫的快照。這個一致性視圖會記錄當前事務開始時已經提交的數據版本。

當執行查詢操作時,MySQL會根據事務的一致性視圖來決定可見的數據版本。只有那些在事務開始之前已經提交的數據版本才是可見的,未提交的數據或在事務開始后修改的數據則對當前事務不可見。

實現事務隔離

那么MVCC在MySql中又是怎么樣實現事務隔離的呢?

對于讀未提交隔離級別,不做任何控制,相當于是一級封鎖協議,修改語句會默認添加排他鎖,并且在事務結束時才會釋放。

對于讀已提交隔離級別,MVCC通過Read View來實現。(具體看Read View)

對于可重復讀隔離級別,MVCC通過Read View來實現。(具體看Read View)

對于串行化隔離級別,通過加臨健鎖(行鎖+間隙鎖)來實現的。

Read View

首先我們先要了解數據庫的表記錄,除了原來的數據列以外,還維護了3個隱藏列,和Read View相關的只有兩個隱藏列,我們只關注這兩個,一個是DB_TRX_ID,還有一個是DB_ROLL_PTR,其中DB_TRX_ID表明這條記錄所屬的事務id,DB_ROLL_PTR指向這條事務上一個事務所保存的這條記錄的快照。所以對于一條記錄,我們有一個多版本快照鏈(由DB_ROLL_PTR串聯成鏈,讀取選擇讀哪條的時候靠的是DB_TRX_ID來選擇)。有了這個多版本快照鏈,事務在進行快照讀的時候,就會結合Read View所記錄的活躍的事務信息,選擇當前隔離級別下可見的最新的記錄了。

Read View就是mvcc實現快照讀的核心機制,我們借助它就可以去undo_log中尋找要讀的這條記錄在當前事務隔離級別下"可見"的那個版本。下圖就是一個Read View,它其實就是記錄了事務的信息。

在這里插入圖片描述

使用這個Read View的時候有一些規則:

(首先我們要知道每次讀取記錄的時候其實都是去當前這個記錄的undo_log中去讀取的,每次都先讀取最新的版本,然后結合Read View進行判斷,如果最新版本的不可讀就會沿著版本鏈讀取下一個版本直到可讀。)

  1. 如果版本的記錄的事務id是當前執行讀取操作的事務id,則直接讀取。

  2. 如果版本的記錄的事務id小于Read View中的min_trx_id,那么表明該版本是在當前的讀取事務開始之前就提交了的,可以讀。

  3. 如果版本的記錄的事務id大于Read View中保存的max_trx_id,那么表明該版本是在當前讀取操作的事務開始之后提交的,不能讀取。

  4. 如果當前讀取操作的事務id位于Read View中記錄的min_trx_id到max_trx_id之間,那么就表明這個版本是在當前活躍的但是還未提交的版本中的,那么只要在讀已提交版本之上,就也不可以讀。

讀已提交可重復讀 有一個很大的區別就是讀已提交在每次讀取操作的時候都會創建一個新的當前狀態的Read View,而可重復讀只會再事務第一次讀取操作之后創建一個Read View,并且使用這個Read View一直到事務結束。就是這個區別使得 讀已提交 可能導致 不可重復讀 的問題。因為第二次讀取使用的是一個更新后的新 Read View,可能讀到了其他事務剛剛提交的新值。

總結

因此,有了MVCC,有了Read View,我們可以無鎖地實現事務隔離級別,在讀取操作地時候不上鎖(沒有MVCC的話,讀取的時候要使用共享鎖來進行控制),只有在修改操作的時候正常加上排他鎖,大大地提高了并發事務的性能。

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

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

相關文章

小架構step系列18:工具

1 概述 在寫代碼的時候,有很多通用的、與業務無關邏輯,這些一般寫成工具類方法。這些工具類方法慢慢地被積累起來,變成了開源包,可以直接使用開源包,而不是自己再花時間來重復造這些輪子。 這些工具類的開源包比較多…

網絡、CentOS 系統、數據庫面試知識點總結

文章目錄Linux CentOS 面試知識點整理速查復習? 一、Linux 高頻面試題? 二、MySQL 高頻面試題? 三、計算機網絡(OSI四層模型)高頻面試題🔗 鏈路層(Link Layer)🌐 網絡層(Internet Layer&…

Vue (Official) v3.0.2 新特性 為非類npm環境引入 globalTypesPath 選項

目錄 前言 報錯信息 原因 解決方案 總結 前言 在早上更新了vscode后,發現自己 uni-app 項目的 .vue文件 的 template 標簽都出現了報錯。定位到了問題是因為 Vue (Official) 插件更新導致的,重裝了插件的上一個小版本,報錯消失&#xff…

程序可能的輸出

#include "csapp.h"int main() {int x 3;if (Fork() ! 0)printf("x%d\n", x);printf("x%d\n", --x);exit(0); }分析:父進程先執行printf("x%d\n", x); 輸出x4。后執行 printf("x%d\n", --x);輸出x3。子進程只執…

2025年UDP應用抗洪指南:從T級清洗到AI免疫,實戰防御UDP洪水攻擊

一次未防護的UDP暴露,可能讓日活百萬的應用瞬間癱瘓,損失超千萬2025年,隨著物聯網僵尸網絡規模指數級增長及AI驅動的自適應攻擊工具泛濫,UDP洪水攻擊峰值已突破8Tbps,單次攻擊成本卻降至50元以下。更致命的是&#xff…

centos7安裝MySQL8.4手冊

目錄前言一、首先更新插件,并查看當前系統版本二、安裝步驟1、創建mysql目錄2、安裝rpm包3、安裝 mysql-community-server4、啟動MySQL服務5、查看MySQL狀態6、設置開機自啟動三、查看默認密碼四、登錄mysql五、修改密碼六、開啟遠程訪問1. 修改 MySQL 配置文件2. 重…

人臉檢測算法——SCRFD

SCRFD算法核心解析 1. 算法定義與背景 SCRFD(Sample and Computation Redistribution for Efficient Face Detection)由Jia Guo等人于2021年在arXiv提出,是一種高效、高精度的人臉檢測算法,其核心創新在于: 雙重重分…

vue3+ts+elementui-表格根據相同值合并

代碼<div style"height: auto; overflow: auto"><el-table ref"dataTableRef" v-loading"loading" :data"pageData" highlight-current-row borderselection-change"handleSelectionChange" :span-method"obj…

UI前端與數字孿生融合案例:智慧城市的智慧停車引導系統

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;停車難的 “城市痛點” 與數字孿生的破局之道當司機在商圈繞圈 30 分鐘仍…

java+vue+SpringBoot集團門戶網站(程序+數據庫+報告+部署教程+答辯指導)

源代碼數據庫LW文檔&#xff08;1萬字以上&#xff09;開題報告答辯稿ppt部署教程代碼講解代碼時間修改工具 技術實現 開發語言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot數據庫&#xff1a;mysql 開發工具 JDK版本&#xff1a;JDK1.8 數…

【Docker基礎】Docker-compose從入門到精通:安裝指南與核心命令全解析

目錄 前言 1 Docker-compose核心概念解析 1.1 什么是Docker-compose&#xff1f; 1.2 典型應用場景 2 Docker-compose離線安裝詳解 2.1 離線安裝背景與優勢 2.2 詳細安裝步驟 步驟1&#xff1a;獲取離線安裝包 步驟2&#xff1a;文件部署與權限設置 步驟3&#xff1a…

面試150 被圍繞的區域

思路 使用DFS&#xff0c;將所有與邊界相連的’O’都修改為‘#’,然后遍歷數組&#xff0c;如果是遇到’#‘修改為’O’,如果是’O’修改為’X’。 class Solution:def solve(self, board: List[List[str]]) -> None:"""Do not return anything, modify boar…

(數據結構)線性表(上):SeqList 順序表

線性表&#xff08;上&#xff09;&#xff1a;Seqlist 順序表基本了解線性表順序表靜態順序表動態順序表編寫動態順序表項目結構基礎結構初始化尾插頭插尾刪頭刪查找指定位置pos之前插入數據刪除指定位置pos的數據銷毀完整代碼SeqLIst.hSeqLIst.ctest.c算法題移除元素刪除有序…

WebStorm vs VSCode:前端圈的「豆腐腦甜咸之爭」

目錄 一、初識兩位主角&#xff1a;老司機與新勢力 二、開箱體驗&#xff1a;是「拎包入住」還是「毛坯房改造」 三、智能提示&#xff1a;是「知心秘書」還是「百度搜索」 四、調試功能&#xff1a;是「CT 掃描儀」還是「聽診器」 五、性能表現&#xff1a;是「重型坦克」…

C#將類屬性保存到Ini文件方法(利用拓展方法,反射方式獲取到分組名和屬性名稱屬性值)

前言&#xff1a;最近學習C#高級課程&#xff0c;里面學到了利用反射和可以得到屬性的特性、屬性名、屬性值&#xff0c;還有拓展方法&#xff0c;一直想將學到的東西利用起來&#xff0c;剛好今天在研究PropertyGrid控件時&#xff0c;想方便一點保存屬性值到配置文件&#xf…

kafka 單機部署指南(KRaft 版本)

目錄環境準備JDK安裝下載jdkjdk安裝kafka 部署kafka 下載kafka 版本號結構解析kafka 安裝下載和解壓安裝包配置 KRaft 模式格式化存儲目錄啟動kafkaKafka 配置為 systemd 服務注意事項調整 JVM 內存參數Kafka KRaft 版本&#xff08;即 Kafka 3.0 及更高版本&#xff09;使用 K…

websocket案例 599足球比分

目標地址:aHR0cHM6Ly93d3cuNTk5LmNvbS9saXZlLw接口:打開控制臺 點websocket 刷新頁面 顯示分析:不寫理論了關于websocket 幾乎發包位置都是下方圖片 不管抖音還是快手 等平臺這里在進行 new WebSocket 后 是要必須走一步的 也就是 new WebSocket().onopen() 也就是onopen 進行向…

【后端】Linux系統發布.NetCore項目

目錄 1.設置全球化不變模式 1.發布到文件 3. 配置為服務 3.1.添加服務 3.2.添加執行權限 3.3.啟動服務 4.訪問 1.設置全球化不變模式 雙擊所需項目&#xff0c;設置全球化不變模式 <!-- 設置全球化不變模式 --><RuntimeHostConfigurationOption>System.Globa…

CMU-15445(2024fall)——PROJECT#0

題目介紹 這是題目原文。 注意&#xff1a;在拉取項目的時候需要注意拉取2024fall的Tag&#xff0c;本人血淚教訓&#xff01; 本題是關于HyperLogLog的具體實現&#xff0c;其介紹可以看這個視頻進行了解。簡單來說HyperLogLog可以在一個非常小的固定內存下&#xff08;一般…

使用微信免費的圖像處理接口,來開發圖片智能裁剪和二維碼/條碼識別功能,爽歪歪

大家好&#xff0c;我是小悟。 1、圖片智能裁剪 我們先來了解一下圖片智能裁剪。圖片智能裁剪聚焦于數字圖像的智能化處理。AI技術的引入徹底改變了傳統依賴人工框選的裁剪模式。 通過深度學習模型自動識別圖像主體&#xff08;人物、商品等&#xff09;&#xff0c;能在極短時…