Mysql的事務是什么?

簡單來說,MySQL 實現事務的核心就像是給你的數據庫操作加了一套“保險和存檔”機制。它確保了你的操作要么全部成功,要么全部失敗,并且在面對多人同時操作、系統突然崩潰等情況時,數據依然可靠、準確。

為什么需要事務呢?想象一下銀行轉賬:你從A賬戶取出100元,然后存入B賬戶。這其實是兩個步驟:

  1. A賬戶余額 - 100元。
  2. B賬戶余額 + 100元。

如果第一個步驟成功了,第二個步驟因為系統崩潰失敗了,那這100元就憑空消失了!這顯然不能接受。事務就是為了解決這類問題,它把這些操作“打包”成一個不可分割的整體。

MySQL(特別是其默認且最常用的存儲引擎InnoDB)通過以下“四大法寶”來確保事務的可靠性:

  1. 原子性 (Atomicity):保證操作要么全成功,要么全失敗。
  2. 一致性 (Consistency):保證事務前后數據都符合規則。
  3. 隔離性 (Isolation):保證多個事務互不干擾,像獨立運行一樣。
  4. 持久性 (Durability):保證事務一旦提交,數據就永遠不會丟失。

接下來,我們就一步一步揭開這些法寶的神秘面紗。


一、 原子性 (Atomicity):要么全生,要么全死

核心思想: 事務里的所有操作,就像一個“生死與共”的團隊。要么這個團隊所有成員都成功完成任務,要么任務失敗,所有成員的狀態都回到任務開始前,就好像他們從來沒做過一樣。

MySQL 如何實現?

MySQL 主要依靠 Undo Log(回滾日志) 來實現原子性。

想象一下你是一個藝術家,正在畫布上創作一幅畫。每次你畫一筆(執行一個DML操作,如UPDATE、DELETE、INSERT),在動筆之前,你都會把這一筆之前畫布的樣子用拍立得拍下來,并貼在你的“回溯日記本”里。

  • 如果你畫得很順利,最終完成了,你就可以把這些拍立得扔掉了(事務提交,Undo Log就不需要了)。
  • 如果你畫到一半發現畫錯了,或者突然不想畫了(事務回滾或系統崩潰),你就可以翻開“回溯日記本”,找到最近一次拍的照片,把畫布恢復成那張照片的樣子,就好像你從未畫錯一樣。

Undo Log 的作用:

  • 數據回滾: 當事務回滾時,InnoDB會讀取Undo Log,將數據恢復到事務開始前的狀態。
  • MVCC(多版本并發控制): 這是后面隔離性中會講到的一個重要概念。Undo Log也保存了數據的歷史版本,供其他事務進行“快照讀”。

事務提交/回滾的流程(簡化版):


(例如: 錯誤/回滾)
事務開始: T1
執行SQL操作1: UPDATE 賬戶A
記錄原始值到Undo Log
(例如: 賬戶A原值=1000)
執行SQL操作2: INSERT 交易記錄
記錄原始值到Undo Log
(例如: 交易記錄無,回滾則刪除)
所有操作完成?
事務提交
清空Undo Log
操作生效并持久化
(通過Redo Log等)
事務回滾
根據Undo Log
恢復數據到事務開始前狀態

專家視角: 原子性是事務的基石。沒有原子性,一致性、隔離性和持久性都無從談起。Undo Log不僅是實現原子性的關鍵,它還是MVCC實現隔離性的重要支撐,因為它存儲了數據的歷史版本。


二、 一致性 (Consistency):萬變不離其宗

核心思想: 事務執行前后,數據庫的數據狀態必須從一個一致性狀態轉換到另一個一致性狀態。這意味著所有預設的規則(比如賬戶余額不能為負數、訂單號不能重復、外鍵關系不能被破壞等)都必須得到遵守。

MySQL 如何實現?

一致性不是由某個單一的機制直接實現的,它是原子性、隔離性、持久性共同作用的結果,加上數據庫本身的約束和應用層的業務邏輯來保證的。

  • 原子性 確保了要么所有操作成功,要么都回滾,避免了中間狀態的暴露。
  • 隔離性 確保了并發操作時,事務不會看到其他事務的中間狀態,從而避免了臟數據。
  • 持久性 確保了提交后的數據不會丟失,也就不會導致數據不一致。
  • 數據庫約束: PRIMARY KEY (主鍵)、UNIQUE KEY (唯一鍵)、FOREIGN KEY (外鍵)、NOT NULL (非空) 等。這些約束是數據庫層面強制執行的規則。
  • 業務邏輯: 應用程序代碼中實現的復雜業務規則(例如,轉賬時檢查賬戶余額是否充足)。

一致性就像是建筑的藍圖。無論你對建筑進行什么操作(加蓋、拆除),最終的結構都必須符合藍圖的規定(比如承重墻不能拆,安全門必須保留)。如果操作導致不符合藍圖,就必須撤銷(回滾)。

一致性更多的是一個目標,是數據庫系統和應用系統共同維護的一種狀態。它確保了數據的合法性和有效性。當原子性、隔離性、持久性都得到保障時,數據自然傾向于保持一致性。


三、 隔離性 (Isolation):井水不犯河水

核心思想: 當多個事務同時操作數據庫時,每個事務都感覺自己是唯一在操作的。一個事務的中間狀態對其他事務是不可見的,就像它們被“隔離”在一個個獨立的房間里。

MySQL 如何實現?

隔離性是事務中最復雜的部分,因為它需要在并發性和數據正確性之間找到平衡。MySQL (InnoDB) 主要通過兩種機制來實現:

  1. 鎖 (Locks):最直接的隔離手段,通過“搶占資源”來避免沖突。

    • 共享鎖 (S Lock):多個事務可以同時持有,用于讀操作。
    • 排他鎖 (X Lock):只有一個事務可以持有,用于寫操作,會阻塞其他讀寫操作。
    • 粒度: 表鎖(鎖住整張表)、行鎖(鎖住特定行)。InnoDB 默認使用行鎖,粒度更細,并發性更高。
  2. 多版本并發控制 (MVCC - Multi-Version Concurrency Control)

    • 核心思想: 允許多個事務同時讀取數據的不同“版本”,而不是直接阻塞。就像每次修改數據時都創建一個新版本,舊版本仍然保留著,供正在讀取的事務使用。這大大提高了并發性能。
    • MVCC 依賴:
      • Undo Log: 前面提到了,存儲著數據的歷史版本。
      • 隱藏字段: InnoDB 每行數據都會增加幾個隱藏字段:
        • DB_TRX_ID:記錄最近一次修改該行的事務ID。
        • DB_ROLL_PTR:回滾指針,指向該行上一個版本的Undo Log記錄。
        • DB_ROW_ID:行ID(如果表沒有主鍵,InnoDB會生成一個隱藏的主鍵)。
      • Read View (讀視圖): 一個在事務開始時生成的“快照”,決定當前事務能看到哪些版本的數據。它包含當前活躍的事務ID列表。

MVCC 的工作原理(快照讀):
當一個事務進行“快照讀”(普通SELECT語句)時,它不是直接讀取最新的數據,而是根據自己的 Read View 和數據的 DB_TRX_IDDB_ROLL_PTR,沿著Undo Log鏈條找到一個它“應該”看到的數據版本。

隔離級別: 數據庫標準定義了四種隔離級別,隔離性從弱到強,并發性從強到弱:

  • 讀未提交 (Read Uncommitted):可以看到其他事務未提交的數據(臟讀)。基本不用。
  • 讀已提交 (Read Committed):只能看到其他事務已提交的數據。但同一個事務內,多次讀取可能看到不同結果(不可重復讀)。Oracle 默認級別。
  • 可重復讀 (Repeatable Read):同一個事務內,多次讀取同一數據會看到相同結果,避免了不可重復讀。但可能出現幻讀(行數變化)。MySQL (InnoDB) 默認級別。
    • 實現: 事務開始時生成 Read View,整個事務期間都用這個 Read View
  • 串行化 (Serializable):最高級別,強制事務串行執行,完全避免臟讀、不可重復讀、幻讀。并發性能最低。
    • 實現: 對所有讀操作加共享鎖,寫操作加排他鎖。

MVCC 如何避免“不可重復讀”和“幻讀”?

  • 不可重復讀: 在“可重復讀”隔離級別下,MVCC通過 Read View 的固定來解決。事務T1開始時生成一個 Read View,即使事務T2修改了數據并提交,T1仍然通過自己的 Read View 看到T2修改前的數據版本,從而實現了可重復讀。
  • 幻讀: MVCC只能解決快照讀的幻讀問題。對于當前讀SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE)仍然會存在。MySQL 在“可重復讀”隔離級別下,通過間隙鎖 (Gap Lock)Next-Key Lock (行鎖+間隙鎖) 來徹底解決幻讀問題。

MVCC 讀取數據的流程圖:

T1可見
T1不可見
T1可見
T1不可見
事務T1開始
生成Read View(RV)
T1執行SELECT
(快照讀)
讀取數據行D的最新版本
比較D.DB_TRX_ID
與RV活躍事務列表
返回數據D給T1
沿著D.DB_ROLL_PTR
追溯到Undo Log中的上一版本
比較上一版本D'的DB_TRX_ID
與RV活躍事務列表
返回數據D'給T1
繼續追溯到更早版本
直到找到可見版本或無版本
找到可見版本?
數據對T1不可見

專家視角: 隔離性是并發控制的核心挑戰。MVCC的引入是數據庫發展的重要里程碑,它極大地提高了數據庫的并發處理能力,讓讀寫操作可以在大部分情況下互不阻塞。鎖和MVCC是互補的,鎖用于需要嚴格同步的“當前讀”和寫操作,MVCC用于高性能的“快照讀”。


四、 持久性 (Durability):言出法隨,一字千金

核心思想: 事務一旦提交,它對數據庫的所有修改就是永久性的。即使系統崩潰、斷電,這些修改也必須能夠恢復,不會丟失。

MySQL 如何實現?

MySQL (InnoDB) 主要通過 Redo Log(重做日志)WAL (Write-Ahead Logging) 機制來確保持久性。

想象一下你是一個重要的會議記錄員。會議上做出的所有決定(數據修改),你不是等會議全部結束才整理成正式文件,而是每當有一個新決定拍板時,你立即用最快的速度記在一本“快速筆記”(Redo Log)上。這本筆記會定期同步到正式的“會議記錄本”(數據文件)。

即使會議進行到一半突然停電,你也可以根據這本“快速筆記”恢復到停電前所有的已批準決定,而不會丟失任何內容。

Redo Log 的作用:

  • 崩潰恢復: 當數據庫在事務提交后、數據頁還沒來得及從內存刷寫到磁盤時崩潰,重啟后可以通過Redo Log將這些已提交但未持久化的修改重新應用到數據文件中,確保數據不丟。
  • 提高性能: Redo Log是順序寫入的,速度非常快。它允許事務提交時只將Redo Log刷盤(相對數據文件隨機寫磁盤更快),而數據頁的刷盤可以延遲進行。

Redo Log 刷盤策略 (InnoDB_flush_log_at_trx_commit):

  • 0:事務提交時,Redo Log 寫入日志緩沖區,并每秒刷盤一次。性能好,但可能丟失1秒數據。
  • 1:事務提交時,Redo Log 寫入日志緩沖區,并立即刷盤。安全性最高,但性能最差。
  • 2:事務提交時,Redo Log 寫入日志緩沖區,然后寫到OS Cache,OS每秒刷盤一次。折中方案。

WAL (Write-Ahead Logging) 原則:
先寫日志,再寫數據。即 Redo Log 必須先于對應的數據頁刷盤。這是確保持久性的關鍵原則。

Double Write Buffer(雙寫緩沖區):
這是一個額外的保護機制,防止“部分寫失效”問題。當數據頁從Buffer Pool刷寫到磁盤時,不是直接寫到數據文件,而是先寫到Double Write Buffer(一個連續的區域),然后再寫到真正的數據文件。這樣即使在數據頁寫入過程中發生崩潰,也可以從Double Write Buffer中恢復完整的數據頁。

持久化流程圖:

已提交
未刷盤數據頁
未提交事務
客戶端提交事務
數據修改
(在內存Buffer Pool中)
將修改內容寫入Redo Log Buffer
(內存中)
事務提交
Redo Log Buffer內容刷寫到磁盤Redo Log文件
(遵循WAL原則)
事務提交成功,返回客戶端
后臺線程異步將Buffer Pool中修改過的數據頁
刷寫到磁盤數據文件
(可能通過Double Write Buffer)
數據庫崩潰/斷電
數據庫重啟
檢查Redo Log文件
發現未完全刷盤的已提交事務
或未完成的事務?
通過Redo Log重做這些操作
恢復數據一致性
通過Undo Log回滾這些操作
數據庫恢復完成,對外服務

持久性是數據庫系統最重要的承諾之一。Redo Log和WAL機制是實現這一承諾的核心,它們在保證數據不丟失的同時,也通過日志的順序寫入特性提升了性能。數據庫的恢復能力是其健壯性的重要體現。


MySQL (InnoDB) 實現事務的四大特性,是一套精妙且協同工作的復雜系統。它不是依靠單一技術,而是通過多種機制的組合與協作:

  • Undo Log:是原子性(回滾)和隔離性(MVCC 多版本)的基石。
  • Redo Log:是持久性(崩潰恢復)和高性能寫入的保障。
  • 鎖機制:是隔離性的直接手段,解決并發沖突,特別是“當前讀”的隔離。
  • MVCC:是隔離性的高級實現,通過多版本數據和 Read View 提升并發性能。
  • WAL原則、Double Write Buffer、事務隔離級別、數據庫約束等,都是這套系統的重要組成部分。

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

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

相關文章

測試開發:Python+Django實現接口測試工具

【測試開發天花板】DjangoVuePyTest打造企業級自動化平臺|能寫進簡歷的硬核項目最近被幾個公司實習生整自閉了,沒有基礎,想學自動化又不知道怎么去學,沒有方向沒有頭緒,說白了其實就是學習過程中沒有成就感&#xff0c…

TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》

核心思想 這篇論文的核心思想是提出一種全新的、數據驅動的自主模糊聚類(Autonomous Fuzzy Clustering, AFC)算法。其核心創新在于,它巧妙地結合了模糊聚類的靈活性和基于中位數(medoids)聚類的可解釋性,并…

ELK是什么

ELK 是一個廣受歡迎的開源技術棧,用于實時采集、處理、存儲、搜索、分析和可視化海量的日志數據(log)和機器生成的數據(machine data),尤其是在 IT 系統監控、應用故障排查、安全分析和業務智能等領域應用廣…

[硬件電路-123]:模擬電路 - 信號處理電路 - 常見的高速運放芯片、典型電路、電路實施注意事項

一、高速運放常見芯片型號及特性高速運放(高速運算放大器)通常指帶寬(GBW)超過10MHz、壓擺率(SR)高于10V/μs的器件,適用于視頻處理、通信系統、高速數據采集等場景。以下是典型芯片及其特性&am…

關于解決WinRiver項目動態XmlElement的序列化與反序列化的問題

關于解決WinRiver項目動態XmlElement的序列化與反序列化的問題 一、WinRiver項目流量匯總XML內容 1.1、索引可變,索引下 XmlElement 元素內容固定 1.2、如何將對象 BottomTrack 的動態內容序列化為 XML ? 1.3、如何將 XML 動態內容反序列化為對象 BottomTrack ? 二、XML 動態…

【力扣 Hot100】 刷題日記

D3 128.最長連續序列 錯解 class Solution {public int longestConsecutive(int[] nums) {Arrays.sort(nums);int maxCnt 0;int cnt 0;for (int i 0; i < nums.length - 1; i) {if(nums[i] ! nums[i 1] - 1){//如果不連續&#xff0c;取cnt與maxCnt較大值&#xff0c…

飛算JavaAI編程插件:以AI之力賦能Java開發,讓編碼效率再升級

你是否希望自己敲代碼的時候總有一位大佬在你背后幫你保駕護航。想象一下&#xff0c;當你對著Java編輯器敲代碼時&#xff0c;身后站了位“隱形大神”——你剛敲出for&#xff0c;它就預判到你要遍歷集合&#xff0c;自動補全帶泛型的循環邏輯&#xff1b;你手滑把equals寫成&…

機器學習通關秘籍|Day 03:決策樹、隨機森林與線性回歸

目錄 一、決策樹 1、概念 2、基于信息增益的決策樹的建立 &#xff08;1&#xff09;信息熵 &#xff08;2&#xff09;信息增益 &#xff08;3&#xff09;信息增益決策樹建立步驟 3、基于基尼指數的決策樹的建立 4、API 二、隨機森林 1、算法原理 2、API 三、線性…

C++進階—C++的類型轉換

第一章&#xff1a;C語言中的類型轉換在C語言中&#xff0c;如果賦值運算符左右兩側類型不同&#xff0c;或者形參與實參類型不匹配&#xff0c;或者返回值類型與接收返回值類型不一致時&#xff0c;就需要發生類型轉化&#xff0c;C語言中總共有兩種形式的類型轉換&#xff1a…

基于Flask的微博話題多標簽情感分析系統設計

基于Flask的微博話題情感分析系統設計與實現 一、項目概述 本項目是一個輕量化的微博話題情感分析系統&#xff0c;通過Flask框架整合情感分析模型&#xff0c;實現對微博話題及評論的情感標簽識別與結果展示。系統面向普通用戶和研究者&#xff0c;提供簡單易用的操作界面&…

TDengine 中 TDgpt 的模型評估工具

模型評估工具 TDgpt 在企業版中提供預測分析模型和異常檢測模型有效性評估工具 analytics_compare&#xff0c;該工具能夠使用 TDengine 中的時序數據作為 回測依據&#xff0c;評估不同預測模型或訓練模型的有效性。該工具在開源版本中不可用使用評估工具&#xff0c;需要在其…

【DL學習筆記】DataLoader類功能和參數說明

文章目錄一、Dataset 與 DataLoader 功能介紹抽象類Dataset的作用DataLoader 作用兩者關系二、torch.utils.data.DataLoader代碼示例常用參數圖示num_workers設置多少合適數據加載子進程如何并行的pin_memorysampler兩種sampler順序采樣 SequentialSampler隨機采樣 RandomSampl…

JVM中年輕代、老年代、永久代(或元空間)、Eden區和Survivor區概念介紹

在Java虛擬機&#xff08;JVM&#xff09;中&#xff0c;內存管理是自動化的&#xff0c;這主要通過垃圾回收機制實現。JVM將堆內存劃分為不同的區域&#xff0c;以便更高效地管理和回收對象。以下是關于年輕代、老年代、永久代&#xff08;或元空間&#xff09;、Eden區和Surv…

譯 | BBC Studios團隊:貝葉斯合成控制方法SCM的應用案例

來自上傳文件中的文章《Using Causal Inference for Measuring Marketing Impact: How BBC Studios Utilises Geo Holdouts and CausalPy》 本篇介紹了在傳統A/B測試不適用時&#xff0c;如何利用貝葉斯合成控制方法和地理區域保留來評估營銷活動效果。其亮點在于通過構建“反事…

Web開發-PHP應用TP框架MVC模型路由訪問模版渲染安全寫法版本漏洞

我們先使用/index.php/index/index/test&#xff0c;就是圖中的test()方法 /index.php/index/index/index&#xff0c;這個回顯就是111 http://127.0.0.1:83/index.php/index/index/test2?x123456 public function test2() {$x$_GET[x];return $x; } 這里再做一個案例更詳細一…

FreeRTOS列表系統深度解析

FreeRTOS列表系統深度解析 一、核心數據結構 1. 列表控制塊 (List_t) typedef struct xLIST {volatile UBaseType_t uxNumberOfItems; // 當前列表項數量ListItem_t * pxIndex; // 遍歷指針&#xff08;用于輪詢調度&#xff09;MiniListItem_t xListEnd; …

《Linux編譯器:gcc/g++食用指南》

堅持用 清晰易懂的圖解 代碼語言&#xff0c;讓每個知識點變得簡單&#xff01; &#x1f680;呆頭個人主頁詳情 &#x1f331; 呆頭個人Gitee代碼倉庫 &#x1f4cc; 呆頭詳細專欄系列 座右銘&#xff1a; “不患無位&#xff0c;患所以立。” 《Linux編譯器&#xff1a;GCC…

SparkKV轉換算子實戰解析

目錄 KV算子 parallelizePairs mapToPair mapValues groupByKey reduceByKey sortByKey 算子應用理解 reduceByKey和groupByKey的區別 groupByKeymapValues實現KV數據的V的操作 改進用reduceByKey groupby通過K和通過V分組的模板代碼 問題集錦 寶貴的經驗 這里會…

深度解析 TCP 三次握手與四次揮手:從原理到 HTTP/HTTPS 的應用

TCP 的三次握手和四次揮手是網絡通信的基石&#xff0c;無論是 HTTP 還是 HTTPS&#xff0c;它們都依賴 TCP 提供可靠的傳輸層服務。本文將用萬字篇幅&#xff0c;結合 Mermaid 圖表和代碼示例&#xff0c;深入講解 TCP 三次握手、四次揮手的原理、過程、狀態變化&#xff0c;以…

Hyper-V + Centos stream 9 搭建K8s集群(一)

一、創建虛擬機一臺32G內存&#xff0c;16核心的Win11&#xff0c;已經安裝了Hyper-V 管理器。然后也下載了CentOS-Stream-9-latest-x86_64-dvd1.iso的鏡像文件。這里Hyper-V創建虛擬機的過程就不贅述了&#xff0c;如果出現虛擬機加載不到鏡像的問題&#xff0c;先把這個使用安…