MySQL InnoDB的事務隔離與鎖

2022-09-07 05:27:09 字數 4097 閱讀 7605

關於索引結構,前面有一篇文章:

mysql索引原理總結

mvcc

mysql innodb儲存引擎,實現的是基於多版本的併發控制協議——mvcc (multi-version concurrency control) 讀不加鎖,讀寫不衝突。(與mvcc相對的,是基於鎖的併發控制,lock-based concurrency control)。

讀操作分:快照讀 (snapshot read)與當前讀 (current read)。

快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不加鎖。

當前讀,讀取的是記錄的最新版本,並且,返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄。

當前讀:插入/更新/刪除操作(中包含一次讀操作,讀當前最新版本)或顯式加鎖,需要加鎖。

所有以上的語句,都屬於當前讀,讀取記錄的最新版本。並且,讀取之後,還需要保證其他併發事務不能修改當前記錄,對讀取記錄加鎖。其中,除了第一條語句,對讀取記錄加s鎖 (共享鎖)外,其他的操作,都加的是x鎖 (排它鎖)。

乙個更新操作在資料庫中的執行流程:

mysql server會根據where條件,讀取第一條滿足條件的記錄,然後innodb引擎會將第一條記錄返回,並加鎖 (current read)。mysql server收到這條加鎖的記錄之後,會再發起乙個update請求,更新這條記錄。一條記錄操作完成,再讀取下一條記錄,直至沒有滿足條件的記錄為止。因此,update操作內部,就包含了乙個當前讀。delete操作也一樣。insert操作會稍微有些不同,insert操作可能會觸發unique key的衝突檢查,也會進行乙個當前讀。

2pl:two-phase locking

加鎖階段只加鎖,解鎖階段只解鎖。

mysql/innodb定義的4種隔離級別:

read uncommited

read committed (rc)

select @@global.tx_isolation;

repeatable read (rr)

serializable

從mvcc併發控制退化為基於鎖的併發控制。不區別快照讀與當前讀,所有的讀操作均為當前讀,讀加讀鎖 (s鎖),寫加寫鎖 (x鎖)。

幾種條件下加鎖情況

兩條sql在幾種組合條件下的加鎖情況:

組合一:id主鍵+rc

組合二:id唯一索引+rc

首先會將unique索引上的id=10索引記錄加上x鎖,同時,會根據讀取到的name列,回主鍵索引(聚簇索引),然後將聚簇索引上的name = 『d』 對應的主鍵索引項加x鎖。

為什麼主鍵索引也要鎖?別的根據主鍵修改感知不到。

組合三:id非唯一索引+rc

首先,id列索引上,滿足id = 10查詢條件的記錄,都加鎖。同時,這些記錄對應的主鍵索引上的記錄也都加鎖。

組合四:id無索引+rc

由於id列上沒有索引,因此只能走聚簇索引,進行全表掃瞄。從圖中可以看到,滿足刪除條件的記錄有兩條,但是,聚簇索引上所有的記錄,都被加上了x鎖。無論記錄是否滿足條件,全部被加上x鎖。

在實際的實現中,mysql有一些改進,在mysql server過濾條件,發現不滿足後,會呼叫unlock_row方法,把不滿足條件的記錄放鎖 (違背了2pl的約束)。這樣做,保證了最後只會持有滿足條件記錄上的鎖,但是每條記錄的加鎖操作不會能省略。

組合五:id主鍵+rr

與組合一:[id主鍵,read committed]一致。

組合六:id唯一索引+rr

與組合二:[id唯一索引,read committed]一致。

組合七:id非唯一索引+rr

相對於組合三:[id列上非唯一鎖,read committed]多了gap鎖,保證其他的事務不會插入新的滿足條件的記錄。

組合八:id無索引+rr

首先,聚簇索引上的所有記錄,都被加上了x鎖。其次,聚簇索引每條記錄間的間隙(gap),也同時被加上了gap鎖。

在這種情況下,這個表上,除了不加鎖的快照度,其他任何加鎖的併發sql,均不能執行,不能更新,不能刪除,不能插入,全表被鎖死。

這個情況下,mysql也做了一些優化,就是semi-consistent read。semi-consistent read開啟的情況下,對於不滿足查詢條件的記錄,mysql會提前放鎖。semi-consistent read生效條件:要麼是read committed隔離級別;要麼是repeatable read隔離級別,同時設定了 innodb_locks_unsafe_for_binlog

引數。但是semi-consistent read本身也會帶來其他問題,不建議使用。

組合九:serializable

對於sql2:delete from t1 where id = 10; 來說,serializable隔離級別與repeatable read隔離級別完全一致。

serializable隔離級別,影響的是sql1:select * from t1 where id = 10; 這條sql,在rc,rr隔離級別下,都是快照讀,不加鎖。但是在serializable隔離級別,sql1會加讀鎖,也就是說快照讀不復存在,mvcc併發控制降級為lock-based cc。

乙個複雜條件的例子

假設rr隔離級別

在repeatable read隔離級別下,由index key所確定的範圍,被加上了gap鎖;index filter鎖給定的條件 (userid = 『hdc』)何時過濾,視mysql的版本而定,在mysql 5.6版本之前,不支援index condition pushdown

(icp),因此index filter在mysql server層過濾,在5.6後支援了index condition pushdown,則在index上過濾。若不支援icp,不滿足index filter的記錄,也需要加上記錄x鎖,若支援icp,則不滿足index filter的記錄,無需加記錄x鎖 (圖中,用紅色箭頭標出的x鎖,是否要加,視是否支援icp而定);而table filter對應的過濾條件,則在聚簇索引中讀取後,在mysql server層面過濾,因此聚簇索引上也需要x鎖。最後,選取出了一條滿足條件的記錄[8,hdc,d,5,good],但是加鎖的數量,要遠遠大於滿足條件的記錄數量。

參考:何登成老師的原文:

MySQL innoDB的事務隔離

關於事務的特性?acid 原子性,一致性 隔離性 永續性。innodb 中的事務的隔離級別?讀提交 乙個事物在已提交的時候才可以被其他事務看到 可重複讀 乙個事務在執行過程中看到的資料,總是跟另個乙個事物在啟動時看到的資料是一致的,只要事務未提交都對其他事務是不可見的。讀未提交 這個事務還未提交就可...

MySQL InnoDB事務模型

事務的acid特性 原子性 一致性 隔離性 永續性。這部分不多說了,任何一本講資料庫理論的書籍裡邊都會有講。mysql innodb通過鎖來實現事務的一致性和隔離性,共實現了四種事務隔離級別 read uncommitted讀取未提交 某個session中的事務可以看到其他session的事務中尚未...

Mysql Innodb事務的隔離級別

隔離級別 髒讀 dirty read 不可重複讀 nonrepeatable read 幻讀 phantom read 解釋未提交讀 read uncommitted 可能可能 可能事務a執行期間能讀到事務b修改且沒有提交的資料。已提交讀 read committed 不可能可能 可能事務a執行期間...