前言
在講解之前,先來思考一個問題——假設有使用者表結構如下:
MySql,InnoDB,Repeatable-Read:users(id PK, name, age KEY)
id | name | age |
---|---|---|
1 | Mike | 10 |
2 | Jone | 20 |
3 | Tony | 30 |
首先事務 A
插入了一行資料,並且沒有 commit
:
INSERT INTO users SELECT 4, 'Bill', 15;
複製程式碼
隨後事務 B
試圖插入一行資料:
INSERT INTO users SELECT 5, 'Louis', 16;
複製程式碼
請問:
- 使用了什麼鎖?
事務 B
是否會被事務 A
阻塞?
預備知識
在瞭解插入意向鎖之前,強烈建議先了解一下意向鎖
和間隙鎖
:
插入意向鎖(Insert Intention Locks)
首先讓我們來看一下 MySql 手冊 是如何解釋 InnoDB 中的插入意向鎖
的:
An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6, respectively, each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.
插入意向鎖
是在插入一條記錄行前,由 INSERT 操作產生的一種間隙鎖
。該鎖用以表示插入意向,當多個事務在同一區間(gap)插入位置不同的多條資料時,事務之間不需要互相等待。假設存在兩條值分別為 4 和 7 的記錄,兩個不同的事務分別試圖插入值為 5 和 6 的兩條記錄,每個事務在獲取插入行上獨佔的(排他)鎖前,都會獲取(4,7)之間的間隙鎖
,但是因為資料行之間並不衝突,所以兩個事務之間並不會產生衝突(阻塞等待)。
總結來說,插入意向鎖
的特性可以分成兩部分:
插入意向鎖
是一種特殊的間隙鎖
——間隙鎖
可以鎖定開區間內的部分記錄。插入意向鎖
之間互不排斥,所以即使多個事務在同一區間插入多條記錄,只要記錄本身(主鍵
、唯一索引
)不衝突,那麼事務之間就不會出現衝突等待。
需要強調的是,雖然插入意向鎖
中含有意向鎖
三個字,但是它並不屬於意向鎖
而屬於間隙鎖
,因為意向鎖
是表鎖而插入意向鎖
是行鎖。
現在我們可以回答開頭的問題了:
- 使用
插入意向鎖
與記錄鎖
。 事務 A
不會阻塞事務 B
。
為什麼不用間隙鎖
如果只是使用普通的間隙鎖
會怎麼樣呢?還是使用我們文章開頭的資料表為例:
MySql,InnoDB,Repeatable-Read:users(id PK, name, age KEY)
id | name | age |
---|---|---|
1 | Mike | 10 |
2 | Jone | 20 |
3 | Tony | 30 |
首先事務 A
插入了一行資料,並且沒有 commit
:
INSERT INTO users SELECT 4, 'Bill', 15;
複製程式碼
此時 users
表中存在三把鎖:
- id 為 4 的記錄行的
記錄鎖
。 - age 區間在(10,15)的
間隙鎖
。 - age 區間在(15,20)的
間隙鎖
。
最終,事務 A
插入了該行資料,並鎖住了(10,20)這個區間。
隨後事務 B
試圖插入一行資料:
INSERT INTO users SELECT 5, 'Louis', 16;
複製程式碼
因為 16 位於(15,20)區間內,而該區間內又存在一把間隙鎖
,所以事務 B
別說想申請自己的間隙鎖
了,它甚至不能獲取該行的記錄鎖
,自然只能乖乖的等待 事務 A
結束,才能執行插入操作。
很明顯,這樣做事務之間將會頻發陷入阻塞等待,插入的併發性非常之差。這時如果我們再去回想我們剛剛講過的插入意向鎖
,就不難發現它是如何優雅的解決了併發插入的問題。
總結
- MySql InnoDB 在
Repeatable-Read
的事務隔離級別下,使用插入意向鎖
來控制和解決併發插入。 插入意向鎖
是一種特殊的間隙鎖
。插入意向鎖
在鎖定區間相同但記錄行本身不衝突的情況下互不排斥。