Mysql學習(六)InnoDB事務原理分析

事務四個特性

原子性(atomicity)

一個事務是一個不可分割的工作單位,事務中包括的諸操作要麼都做,要麼都不做。

InnoDB是如何實現原子性的

通過redolog的持久化以及undolog回滾來保證原子性
在這裏插入圖片描述

redo log保證提交時的數據落盤

redo log 通過Force log at commit 機制保證事務提交後redo log日誌都已經持久化。innodb_flush_log_at_trx_commit需要默認設置爲1纔可以保證原子性。詳細可以參照上一篇博文

undo log保證數據回滾

在這裏插入圖片描述
undo log 分爲兩種,一種是insert undo log,一種是update undo log

insert undo log:

是在 insert 操作中產生的 undo log。 因爲 insert 操作的記錄只對事務本身可見,對於其它事務此記錄是不可見的,所以
insert undo log 可以在事務提交後直接刪除而不需要進行 purge 操作。

在這裏插入圖片描述

update undo log

是 update 或 delete 操作中產生的 undo log。 因爲會對已經存在的記錄產生影響,爲了提供 MVCC機制,因此
update undo log 不能在事務提交時 就進行刪除,而是將事務提交時放到入 history list 上,等待 purge
線程進行最後的刪除操作。

示例:

當事務2使用UPDATE語句修改該行數據時,會首先使用排他鎖鎖定改行,將該行當前的值複製到
undo log中,然後再真正地修改當前行的值,最後填寫事務ID,使用回滾指針指向undo log中修
改前的行。

在這裏插入圖片描述

在這裏插入圖片描述
每次對記錄進行改動,都會記錄一條 undo日誌 ,每條 undo日誌 也都有一個 roll_pointer 屬性
( INSERT 操作對應的 undo日誌 沒有該屬性,因爲該記錄並沒有更早的版本),可以將這些 undo日誌
都連起來,對該記錄每次更新後,都會將舊值放到一條 undo日誌 中,就算是該記錄的一箇舊版本,隨着更新次數
的增多,所有的版本都會被 roll_pointer 屬性連接成一個鏈表,我們把這個鏈表稱之爲 版本鏈 ,版本
鏈的頭節點就是當前記錄最新的值。另外,每個版本中還包含生成該版本時對應的事務id。

爲了保證事務併發操作時,在寫各自的undo log時不產生衝突,InnoDB採用回滾段的方式來維護undo
log的併發寫入和持久化。回滾段實際上是一種 Undo 文件組織方式。

對於使用 InnoDB 存儲引擎的表來說,它的聚簇索引記錄中都包含兩個必要的隱藏列( row_id 並不是
必要的,我們創建的表中有主鍵或者非NULL唯一鍵時都不會包含 row_id 列):

  1. trx_id :每次對某條聚簇索引記錄進行改動時,都會把對應的事務id賦值給 trx_id 隱藏列。
  2. roll_pointer :每次對某條聚簇索引記錄進行改動時,都會把舊的版本寫入到 undo日誌 中,然
    後這個隱藏列就相當於一個指針,可以通過它來找到該記錄修改前的信息。

一致性(consistency)

事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。

實現

過redo log、undo log和Force Log at Commit機制機制來完成

隔離性(isolation)

一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。

實現

InnoDB是由多版本控制機制(MVCC)和鎖實現。

事務的隔離級別

未提交讀(read-uncommitted)

髒讀,就是發生在這一隔離級別下

髒讀:一個事物讀取到其他事物未提交的數據

已提交讀(read-committed)

不可重複讀,就是發生在這一隔離級別下。

不可重複讀:在一個事務中一條記錄,因其他事物修改導致兩次讀取的結果不一樣稱爲不可重複讀

可重複讀(repeatable-read)

可重複讀示意:
repeatable-read

幻讀就發生在這一隔離級別下

幻讀:一個事物因讀取到另一個事物insert,delete的數據,導致同一個條件對一張表的兩次檢索結果不一致。

注意:大多數數據庫,幻讀是在serializable級別下解決的。而MySql是在repeatable-read解決的,原理就是之前博文中講到的間隙鎖

串行化(serializable)

該級別禁止併發性操作,默認對所有的操作都加上鎖。
在這裏插入圖片描述

InnoDB是靠ReadView來保證數據的可見性的

ReadView

  1. 對於使用 READ UNCOMMITTED 隔離級別的事務來說,直接讀取記錄的最新版本就好了。
  2. 對於使用 SERIALIZABLE 隔離級別的事務來說,使用加鎖的方式來訪問記錄。
  3. ReadView主要是針對RC與RR級別的。

ReadView如何解決數據的可見性

其核心問題就是需要判斷一下版本鏈中的哪個版本是當前事務可見的。所以設計 InnoDB 的設計
者提出了一個ReadView的概念,這個 ReadView 中主要包含當前系統中還有哪些活躍1的讀寫事
務,把它們的事務id放到一個列表中,我們把這個列表命名爲m_ids

這樣在訪問某條記錄時,只需要按照下邊的步驟判斷記錄的某個版本(版本鏈中的版本)是否可
見:

  1. 如果被訪問版本的 trx_id 屬性值小於 m_ids 列表中最小的事務id,表明生成該版本的事務在生成
    ReadView 前已經提交,所以該版本可以被當前事務訪問。
  2. 如果被訪問版本的 trx_id 屬性值大於 m_ids 列表中最大的事務id,表明生成該版本的事務在生成
    ReadView 後才生成,所以該版本不可以被當前事務訪問。
  3. 如果被訪問版本的 trx_id 屬性值在 m_ids 列表中最大的事務id和最小事務id之間,那就需要判斷
    一下 trx_id 屬性值是不是在 m_ids 列表中,如果在,說明創建 ReadView 時生成該版本的事務還
    是活躍的,該版本不可以被訪問;如果不在,說明創建 ReadView 時生成該版本的事務已經被提
    交,該版本可以被訪問

那麼問題來了,ReadView是什麼時候生成的呢

ReadView生成時機

readview只會在select操作時產生

  1. 在已提交讀(read-committed)級別中,每次select都會生成一個readview,這樣也很好的說明了,爲什麼RC級別下無法重複讀
  2. 在 可重複讀(repeatable-read)級別中,只有第一次select操作纔會生成readview,所以在一個事物中,針對一條記錄的可見性是不變的,所以是可以重複讀的。

持久性(durability)

持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

實現

同樣是過redo log、undo log和Force Log at Commit機制機制來完成

總結

事務的隔離性由多版本控制機制和鎖實現,而原子性,持久性和一致性主要是通過redo log、undo
log和Force Log at Commit機制機制來完成的。

redo log用於在崩潰時恢復數據,undo log用於對事務的影響進行撤銷,也可以用於多版本控
制。而Force Log at Commit機制保證事務提交後redo log日誌都已經持久化。

注意事項:
開啓一個事務後,用戶可以使用COMMIT來提交,也可以用ROLLBACK來回滾。其中COMMIT或 者ROLLBACK執行成功之後,數據一定是會被全部保存或者全部回滾到最初狀態的,這也體現了事務的原子性。但是也會有很多的異常情況,比如說事務執行中途連接斷開,或者是執行COMMIT或者ROLLBACK時發生錯誤,Server Crash(服務器崩潰)等,此時數據庫會自動進行回滾或者重啓之後進行恢復。

我們再來總結一下數據庫事務的整個流程,如下圖所示

在這裏插入圖片描述
事務的相關流程說明:

  1. 事務進行過程中,每次DML sql語句執行,都會記錄undo log和redo log,然後更新數據形成髒
    頁。
  2. 然後redo log按照時間或者空間等條件進行落盤,undo log和髒頁按照checkpoint進行落盤,落
    盤後相應的redo log就可以刪除了。
  3. 此時,事務還未COMMIT,如果發生崩潰,則首先檢查checkpoint記錄,使用相應的redo log進
    行數據和undo log的恢復,然後查看undo log的狀態發現事務尚未提交,然後就使用undo log進
    行事務回滾。
  4. 事務執行COMMIT操作時,會將本事務相關的所有redo log都進行落盤,只有所有redo log落盤成
    功,纔算COMMIT成功。然後內存中的數據髒頁繼續按照checkpoint進行落盤。如果此時發生了
    崩潰,則只使用redo log恢復數據。

  1. 指的是已經開始還沒有提交的事物,且事物ID生成的時機並不是在事物begin的時候而是在一個事物中第一次對數據增刪改操作。 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章