天天看點

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

作者:ITPUB學院

說起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四大特性。

繼續閱讀