一文帶你看通透,MySQL事務ACID四大特性實現原理

碼農談IT發表於2023-03-13


說起MySQL事務處理的四大特性,相信大家都可以張口就來:ACID!
那 MySQL是如何實現ACID的?每種特性的原理又是如何實現的?
今天,本文筆者主要探討MYSQL InnoDB引擎下的ACID實現原理,對事務、鎖以及隔離級別等內容統一進行回顧一下。

一文帶你看通透,MySQL事務ACID四大特性實現原理


1、ACID特性






  • 原子性(Atomicity)

單個事務,為一個不可分割的最小工作單元,整個事務中的所有操作要麼全部commit成功,要麼全部失敗rollback,對於一個事務來說,不可能只執行其中的一部分SQL操作,這就是事務的原子性。

  • 一致性(Consistency)

資料庫總是從一個一致性的狀態轉換到另外一個一致性的狀態。在前面的例子中, 一致性確保了,即使在執行第三、四條語句之間時系統崩潰,信用卡賬戶也不會損 失100塊,因為事務最終沒有提交,所以事務中所做的修改也不會儲存到資料庫中,保證資料一致性。

  • 隔離性(Isolation)

通常來說,一個事務所做的修改在最終提交以前,對其他事務是不可見(隔離)的。避免多個事務併發執行的時候不會互相干擾。

  • 永續性(Durability)

一旦事務提交,則其所做的修改就會永久儲存到資料庫中,之後的其他操作或故障都不會對事務的結果產生影響。

2、ACID 具體實現






  • 原子性:透過undolog來實現。
  • 永續性:透過binlog、redolog來實現。
  • 隔離性:透過(讀寫鎖+MVCC)來實現。
  • 一致性:MySQL透過原子性、永續性、隔離性最終實現資料一致性。

對MySQL來說,邏輯備份日誌(binlog)、重做日誌(redolog)、回滾日誌(undolog)、鎖技術 + MVCC就是MySQL實現事務的基礎。

2.1  原子性原理

事務通常是以BEGIN TRANSACTION 開始,以 COMMIT 或 ROLLBACK 結束。

  • COMMIT 表示提交,即提交事務的所有操作並持久化到資料庫中。
  • ROLLBACK表示回滾,即在事務中執行的過程中發生了某種故障,事務不能繼續執行,系統將事務中對資料庫所有已完成的操作全部撤銷,回滾到事務開始時的狀態,這裡的操作指對資料庫的更新操作(查詢操作忽略)。這時候需要用到 undolog 來進行回滾。

undolog:
每條資料變更(INSERT/UPDATE/DELETE/REPLACE)等操作都會生成一條undolog記錄,在SQL執行前先於資料持久化到磁碟。

  • insert語句,回滾時會執行 delete;
  • delete語句,回滾時會執行insert;
  • update語句,回滾時便執行相反的update,把資料改回來。

當事務需要回滾時,MySQL會根據回滾日誌對事務中已執行的SQL做逆向操作,比如 DELETE 一行資料的逆向操作就是再把這行資料 INSERT回去,其他操作同理。
undolog記錄事務開始前老版本資料,用於實現回滾,保證原子性,實現MVCC,會將資料修改前的舊版本儲存在undolog,然後行記錄有個隱藏欄位回滾指標指向老版本。

2.2 永續性原理

我們知道,MySQL表資料是持久化到磁碟中的,但如果所有操作都去操作磁碟,等併發上來了,那處理效率無法保證,因此引入了緩衝池(Buffer Pool)的概念,Buffer Pool 中包含了磁碟中部分資料頁的對映,可以當做快取來用;這樣當修改表資料時,我們把操作記錄先寫到Buffer Pool中,並標記事務已完成,等MySQL空閒時,再把更新操作持久化到磁碟裡,從而大大緩解了MySQL併發壓力。
MYSQL的永續性便是由redo log來保證。
redo log
是一種物理日誌,作用:會記錄事務開啟後對資料做的修改,crash-safe。

它類似於一個卸貨的小推車,我們若是每卸一件物品就拿著去入庫,那豈不是特浪費時間,若有一個小推車,我們將貨物首先存放在小推車,當推車滿了再往庫裡存,可以大大提升效率。
其實就是MySQL裡經常說到的WAL技術,WAL的全稱是Write-Ahead Logging,它的關鍵點就是先寫日誌,再寫磁碟,也就是先裝小推車,等不忙的時候再裝庫。

特性空間一定,寫完後會迴圈寫,有兩個指標write pos指向當前記錄位置,checkpoint指向將擦除的位置,redolog相當於是個取貨小車,貨物太多時來不及一件一件入庫太慢了這樣,就先將貨物放入小車,等到貨物不多或則小車滿了或則店裡空閒時再將小車貨物送到庫房。用於crash-safe,資料庫異常斷電等情況可用redo log恢復。
以下只作瞭解:
寫入流程:先寫redo log buffer,然後wite到檔案系統的page cache,此時並沒有持久化,然後fsync持久化到磁碟
寫入策略:根據innodb_flush_log_at_trx_commit引數控制(innodb以事務的什麼提交方式重新整理日誌)

0——>事務提交時只把redo log留在redo log buffer
1——>將redo log直接持久化到磁碟(所以有個雙“1”配置,後面會講)
2——>只是把redo log寫到page cache

2.3 隔離性原理

MYSQL有四種隔離級別,用來解決存在的併發問題:髒讀、幻讀、不可重複讀。


一文帶你看通透,MySQL事務ACID四大特性實現原理

那麼不同隔離級別,隔離性是怎樣實現的呢?
一句話:鎖+MVCC。

  • 表鎖:讀鎖(不會阻塞其他執行緒的讀操作,阻塞寫操作);寫鎖(讀寫操作都阻塞)

  • 行鎖:需要的時候加上,並不是馬上釋放,等事務提交才釋放,兩階段鎖協議

  • 鎖的型別

    • 間隙鎖-gap lock:鎖定區間範圍,防止幻讀,左開右開,只在可重複讀隔離級別下生效—|—為了阻止多個事務將記錄插入到同一範圍內,而這會導致幻讀問題的產生

    • 記錄鎖-record Lock:鎖定行記錄,索的索引,索引失效,為表鎖

    • 臨鍵鎖-next-key Lock:record lock+gap lock 左開右閉(解決幻讀

  • 鎖的模式

    • select .... for update (持有寫鎖,別的不可加讀鎖,也不可加寫鎖)

    • select .... lock in share mode(持有讀鎖,別的可以再加讀鎖,不可加寫鎖)

    • 共享鎖-讀鎖-S鎖

    • 排他鎖-寫鎖-X鎖

    • 意向鎖:讀意向鎖+寫意向鎖

    • 自增鎖

  • 全域性鎖:全庫邏輯備份

  • 死鎖:兩個或多個事務在同一資源上相互佔用,並請求加鎖時,造成相互等待,無限阻塞

MVCC:實現多版本併發控制,實現原理:使用版本鏈+Read View

讀已提交和可重複讀實現原理就是MVCC Read View不同的生成時機。可重複讀只在事務開始時生成一個Read View,之後都用的這個;讀已提交每次執行前都會生成Read View。

2.4 一致性原理

一致性是事務追求的最終目標,前文所述的原子性、永續性和隔離性,其實都是為了保證資料庫狀態的一致性,資料庫中的增刪改操作,使資料庫不斷從一個一致性的狀態轉移到另一個一致性的狀態。

總結






事務該回滾的回滾,該提交的提交,提交後該持久化磁碟的持久化磁碟,該寫緩衝池的寫緩衝池+寫日誌。
對於資料可見性,透過四種隔離級別進行控制,使得庫表中的有效資料範圍可控,保證業務資料的正確性的前提下,進而提高併發程度,支撐服務高QPS的穩定執行,保證資料的一致性,這就是我們們說個不停的MySQL資料庫事務ACID四大特性。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2939349/,如需轉載,請註明出處,否則將追究法律責任。

相關文章