資料庫 MySQL的ReadView

2021-10-17 03:18:19 字數 3446 閱讀 4792

前言

1、根據事務的隔離級別,我們已經知道讀未提交、讀已提交、可重複讀、序列化,隨著隔離級別的加強,能解決髒寫、髒讀、不可重複讀、幻讀的問題。

2、innodb 是 mysql(mysql-5.1版本後) 預設的儲存引擎,innodb 預設的隔離級別就是可重複讀。在這個隔離級別下,開啟事務之後,多次讀寫同一行資料,讀到的值永遠是一致。

3、當 mysql 執行寫操作之前,會把即將被修改的資料記錄到 undo log 日誌裡面。mysql可從 undo log 日誌中,讀取到原插入、修改、刪除之前的值,最終把值重新變回去,這就是回滾操作。

undo log 版本鏈

1、undo log 版本鏈是基於 undo log 實現的。undo log 中主要儲存了資料的基本資訊,比如說日誌開始的位置、結束的位置,主鍵的長度、表id,日誌編號、日誌型別

此外,undo log 還包含兩個隱藏字段 trx_id 和 roll_pointer。trx_id 表示當前這個事務的 id,mysql 會為每個事務分配乙個 id,這個 id 是遞增的。roll_pointer 是乙個指標,指向這個事務之前的 undo log。

2、例子

執行:

insert into student values (1, '張三');
產生:

繼續執行:

update student set name='李四' where id=1;
產生:

繼續執行:

update student set name='王五' where id=1;
產生:

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

readview 機制

readview 其實就是乙個儲存事務id的list列表。記錄的是本事務執行時,mysql還有哪些事務在執行,且還沒有提交。(當前系統中還有哪些活躍的讀寫事務)

它主要包含這樣幾部分:

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

1、trx_id < m_ids列表中最小的事務id

表明生成該版本的事務在生成readview前已經提交,所以該版本可以被當前事務訪問。

2、trx_id > m_ids列表中最大的事務id

表明生成該版本的事務在生成readview 後才生成,所以該版本不可以被當前事務訪問。

3、m_ids列表中最小的事務id < trx_id < m_ids列表中最大的事務id

此處比如m_ids為[5,6,7,9,10]

①、若trx_id在m_ids中,比如是6,說明建立 readview 時生成該版本的事務還是活躍的,該版本不可以被訪問。

②、若trx_id不在m_ids中,比如是8:說明建立 readview 時生成該版本的事務已經被提交,該版本可以被訪問。

一句話說:當trx_id在m_ids中,或者大於m_ids列表中最大的事務id的時候,這個版本就不能被訪問。

如果某個版本的資料對當前事務不可見的話,那就順著版本鏈找到下乙個版本的資料,繼續按照上邊的步驟判斷可見性,依此類推,直到版本鏈中的最後乙個版本,如果最後乙個版本也不可見的話,那麼就意味著該條記錄對該事務不可見,查詢結果就不包含該記錄。

例子:

事務是可以併發執行的,現在有事務 a、事務 b 這兩個事務,且這兩個都沒有提交。事務 a 將會執行多次讀操作,來模擬可重複讀中多次讀取同一行資料的場景。事務 b 則會修改這一行資料。

事務 a 開啟事務的時候會生成乙個 readview,所以說這個 readview 的建立者就是事務 a,事務 a 的事務 id 是 10,所以 creator_trx_id 就是 10。

此時,總共就只有事務 a、事務 b 這兩個事務,而且它們都還沒有提交,所以說 m_ids 會把這兩個事務 id,10、18 都記錄下來。min_trx_id 是 m_ids 裡面的最小值,10、18 中最小的顯然是 10。當前最大的事務 id 是 18,那麼下乙個事務的 id 就是 19,max_trx_id 就是 19。

readview 生成之後,事務 a 就要去 undo log 版本鏈中讀取值了。

現在只有一條 undo log 日誌,但這並不意味著事務 a 就能讀到這條日誌的值 x。它要先判斷這行日誌的 trx_id 是否小於當前事務的 min_trx_id。看圖我們可以很輕鬆地發現,日誌的 trx_id = 8 小於 readview 中 min_trx_id = 10。

這就意味著,這個事務 a 開始執行之前,修改這行資料的事務已經提交了,所以事務 a 是可以查到值 x 的。

在此基礎上再增添一點操作,實現可重複讀

我們繼續看,事務 a 第一次讀完之後,事務 b 要修改這行資料了。undo log 會為所有寫操作生成日誌,所以就會生成一條 undo log 日誌,並且它的 roll_pointer 會指向上一條 undo log 日誌。

緊接著,事務 a 第二次去讀這行資料了,情況如下圖所示:

第一次讀的時候,開啟事務 a 的時候就生成了乙個 readview

此時事務 a 第二次去查詢的時候,先查到的是 trx_id = 18 的那條資料,它會發現 18 比最小的事務編號 10 大。那就說明事務編號為 18 的事務,有可能它是讀不到的。

接著就要去 m_ids 裡確認是否有 18 這條資料了。發現有 18,那就說明在事務 a 開啟事務的時候,這個事務是沒有提交的,它修改的資料就不應該被讀到。

事務 a 就會順著 roll_pointer 指標繼續往下找,找到了 trx_id = 8 這條日誌,發現這條能讀,讀到的值任然是 x,與第一次讀到的結果一致。實現可重複讀。

mysql的資料庫定義 MySQL的資料庫定義語法

建立資料庫 在mysql中,使用 create database 或 create schema 語句建立資料庫 語法結構 create if not exists db name default character set charest name default collate collatio...

mysql資料庫效能資料 MYSQL資料庫效能優化

1.選取最適用的字段屬性 表中字段的寬度設得盡可能小 char 的上限為 255 位元組 固定占用空間 varchar 的上限 65535 位元組 實際占用空間 text 的上限為 65535。盡量把字段設定為 not null,執行查詢的時候,資料庫不用去比較 null 值。2.使用連線 join...

mysql資料庫屬性 MySQL資料庫的三個屬性

mysql資料庫的三個屬性 閱讀 236 mysql資料庫的三個屬性是什麼?一般大家對mysql的了解可能停留在概念的層面上,而對於mysql資料庫三大屬性的了解相對較少。今天就跟大家聊聊mysql資料庫的三大屬性。1 原子性,要求屬性具有原子性,不可再分解。表 欄位1 欄位2 欄位2.1 欄位2....