中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

InnoDB 事務加鎖分析

發布時間:2020-08-03 02:01:16 來源:網絡 閱讀:216 作者:vivo互聯網 欄目:MySQL數據庫

本文首發于 vivo互聯網技術 微信公眾號?
鏈接:https://mp.weixin.qq.com/s/S7MhlsZveBHRSQhq5aTIJA
作者:何志創

一般大家對數據庫事務的了解可能停留在事務的ACID特性以及事務4種不同的隔離級別層面上,而對于事務 4 種不同隔離級別如何實現了解相對較少。

本文以 MySQL 數據庫?InnoDB?引擎為例,為大家分析?InnoDB數據庫引擎對默認的隔離級別可重復讀(RR)的具體實現。

整文知識點介紹:事務4種隔離級別、不同隔離級別解決的問題、MVCC、鎖的類型、加鎖案例分析;閱讀完整文相信大家對事務隔離級別的具體實現有了一定的認識。

一、事務的隔離級別

1、4 種隔離級別

(1)未提交讀(Read uncommitted):一個事務讀取到其他事務未提交的數據,是級別最低的隔離機制;

(2)提交讀(Read committed):一個事務讀取到其他事務提交后的數據;

(3)可重復讀(Repeatable read):一個事務對同一份數據讀取到的相同,不在乎其他事務對數據的修改;

(4)序列化(Serializable) :事務串行化執行,隔離級別最高,犧牲了系統的并發性。

2、不同隔離級別解決的問題

若不考慮事務的隔離級別,則事務的并發會造成以下問題:

(1)臟讀:事務A讀取了事務B更新的數據,然后B回滾操作,那么A讀取到的數據是臟數據。

(2)不可重復讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新并提交,導致事務A多次讀取同一數據時,結果 不一致。

(3)幻讀:同一事務中對同一范圍的數據進行讀取,結果卻多出了數據或者少了數據,這就叫幻讀。(如同一事務對id<10的范圍進行2次查詢,第一次出現id=8、9的兩條數據,第二次出現id=7、8、9的3條數據)。

不可重復讀的和幻讀很容易混淆,不可重復讀側重于修改,幻讀側重于新增或刪除。解決不可重復讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。

不同的隔離級別針對上述3個問題的解決能力,如下表:

InnoDB 事務加鎖分析

二、MVCC

上文提到?InnoDB?默認的隔離級別是可重復讀(RR),InnoDB是通過MVCC(多版本并發控制)來實現可重復讀的,下面為大家介紹MVCC。

1、概念

在InnoDB中,給每行增加兩個隱藏字段來實現MVCC,一個用來記錄數據行的創建時間,另一個用來記錄行的過期時間(刪除時間)。在實際操作中,存儲的并不是時間,而是事務的版本號,每開啟一個新事務,事務的版本號就會遞增。

于是乎,默認的隔離級別(REPEATABLE READ)下,增刪查改變成了這樣:

(1)SELECT

  • 讀取創建版本小于或等于當前事務版本號,并且刪除版本為空或大于當前事務版本號的記錄。這樣可以保證在讀取之前記錄是存在的。

(2)INSERT

  • 將當前事務的版本號保存至行的創建版本號。

(3)UPDATE

  • 新插入一行,并以當前事務的版本號作為新行的創建版本號,同時將原記錄行的刪除版本號設置為當前事務版本號。

(4)DELETE

  • 將當前事務的版本號保存至行的刪除版本號。

2、快照讀和當前讀

(1)快照讀:讀取的是快照版本,也就是歷史版本;

(2)當前讀:讀取的是最新版本。

普通的SELECT就是快照讀,而UPDATE、DELETE、INSERT、SELECT ... ?LOCK IN SHARE MODE、SELECT ... FOR UPDATE是當前讀。

(3)結論:如果隔離級別是REPEATABLE READ,那么在同一個事務中的所有普通select讀讀到的都是事務第一個讀到的快照,如此實現了可重復讀;而對于當前讀(UPDATE、DELETE、INSERT、SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE),InnoDB?通過加鎖來實現可重復讀,且InnoDB?加鎖同時解決了幻讀問題。

三、鎖的類型

InnoDB?引入以下三種鎖類型:

  • Record Locks(記錄鎖):在索引記錄上加鎖,即行鎖,鎖住當前行。

  • Gap Locks(間隙鎖):在索引記錄之間加鎖,或者在第一個索引記錄之前加鎖,或者在最后一個索引記錄之后加鎖。

  • Next-Key Locks:在索引記錄上加鎖,并且在索引記錄之前的間隙加鎖。它相當于是Record Locks與Gap Locks的一個結合。

假設一個索引包含以下幾個值:10,11,13,20。那么這個索引的next-key鎖將會覆蓋以下區間:(-oo, 10]、(10, 11]、(11, 13]、(13, 20]、(20, +oo)。

MySQL?InnoDB?通過間隙鎖解決了幻讀問題。以下通過實際的案例分析來介紹InnoDB?是如果解決幻讀問題的。

四、案例分析

在對SQL進行加鎖分析前,需要明確表的結構和索引類型。在不知道索引的情況下直接給出一條SQL來分析如果加鎖是沒有任何意義的。

以下以用戶表(t_user)為例(id為主鍵,name為唯一索引,age為一般索引,address無索引)分析不同索引條件的加鎖表現。

InnoDB 事務加鎖分析

1、主鍵索引

例:delete from t_user where id=120;
條件為主鍵,此時鎖住聚簇索引中對應的行記錄:即Record Locks鎖住id=120的行記錄。

InnoDB 事務加鎖分析

此種情況下,其他事務除了不能刪除、更新此條記錄外,其他插入其他行、更新其他行都行。

SQL驗證:

InnoDB 事務加鎖分析

2、唯一索引

例:delete from t_user where name='n20';
條件為唯一索引,鎖住索引記錄,同時鎖住聚簇索引中的對應行記錄:

InnoDB 事務加鎖分析

SQL驗證:

InnoDB 事務加鎖分析

3、一般索引

例:delete from t_user where age=20;
與主鍵和唯一索引不同的是,一般索引的記錄是允許重復的;換句話說,如果我們單純地給索引加記錄鎖時,其他事務依然可以插入,也就有可能出現幻讀問題了。

所以除了給對應索引記錄加上記錄鎖之外,還要給Gap加上鎖。

InnoDB 事務加鎖分析

從上面知識點我們可以預估這個操作一共需要的鎖:

  • age索引記錄鎖(Record Lock) :

    20_120, 20_130(以下均用age_id這種形式表示索引值)

  • age索引間隙鎖(Gap X-Lock):

    (10, 20)、(20, 20)、(20, 40)

  • 聚簇索引上的記錄鎖(Record X-Lock):

    id=120/130對應的行記錄

SQL驗證:

InnoDB 事務加鎖分析

根據實際情況,3-6均符合我們預期,然而7和8則超出了我們預期的鎖范圍。為什么會超出我們預期呢?此次我們進行分析一下:

從7、8插入語句來看,由于id為自增主鍵,會自動遞增,語句7插入值預計為:10_141;

語句8插入值預計為:40_141,為什么只有后者能插入呢?
其實我們可以將B+樹中的間隙理解得更加精準一點:

InnoDB 事務加鎖分析

age=20的三個間隙應該為:(10_110, 20_120)、(20_120, 20_130)、(20_130, 40_140);

從上圖可以看出語句7插入值10_141 無法插入,因為間隙被鎖住了;而語句8插入 40_141值因為在間隙之外了,無鎖沖突,允許插入。

所以最終的加鎖情況應該這樣表示:

  • age索引記錄鎖(Record Lock) :20_120, 20_130

  • age索引間隙鎖(Gap X-Lock):(10_110, 20_120)、(20_120, 20_130)、(20_130, 40_140)

  • 聚簇索引上的記錄鎖(Record X-Lock):id=120/130對應的行記錄

4、無索引

delete from t_user where address='a20',因為無法精準定位,InnoDB選擇將聚簇索引中的所有行以及間隙都鎖起來,功能上已經等于鎖表了:

InnoDB 事務加鎖分析

SQL驗證:

InnoDB 事務加鎖分析

5、結論

InnoDB?在RC(READ COMMITTED)隔離級別中,只會在對應的索引/行記錄上加Record Lock,而不會加Gap鎖,原因也很簡單,因為該隔離級別是允許存在幻讀問題的。

在RR級別下的加鎖方式稱之為Next-Key Locks,其實就是上述Record Locks和Gap Locks的結合。比如Gap Lock為(10,20) ,record lock為20,結合的Next-Key lock 為:(10, 20]。

分析Next-Key Locks其實就是要分析Record Locks和Gap Locks。MySQL InnoDB的可重復讀并不保證避免幻讀,需要應用使用加鎖讀來保證。而這個加鎖讀使用到的機制就是next-key locks。

如果使用普通的讀,會得到一致性的結果,如果使用了加鎖的讀,就會讀到“最新的”“提交”讀的結果。本身,可重復讀和提交讀是矛盾的。在同一個事務里,如果保證了可重復讀,

就會看不到其他事務的提交,違背了提交讀;如果保證了提交讀,就會導致前后兩次讀到的結果不一致,違背了可重復讀。可以這么講,InnoDB提供了這樣的機制,在默認的可重復讀的隔離級別里,可以使用加鎖讀去查詢最新的數據。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

巴青县| 保定市| 寿光市| 仪陇县| 佛冈县| 绥滨县| 新郑市| 马公市| 义乌市| 黄梅县| 阆中市| 赤水市| 洛扎县| 石柱| 镇沅| 正蓝旗| 镇赉县| 岱山县| 乾安县| 万全县| 张家口市| 台东市| 贞丰县| 呈贡县| 卫辉市| 宁波市| 南宫市| 佛山市| 黔西| 齐河县| 晋宁县| 潜山县| 株洲县| 格尔木市| 陈巴尔虎旗| 永州市| 牙克石市| 武宁县| 茶陵县| 沙坪坝区| 台江县|