Innodb存儲引擎鎖機制

鎖的類型

Innodb存儲引擎實現瞭如下兩種標準的行級鎖

1)共享鎖(S Lock),允許事務讀一行數據。

2)排它鎖(X Lock),允許事務刪除或更新一行數據。

爲了支持在不同粒度上進行加鎖操作,Innodb支持一種額外的加鎖方式,稱之爲意向鎖(Intention Lock)。意向鎖爲表級別的鎖。設計的目的主要是爲了在一個事務中揭示下一行將被請求的鎖類型。其支持兩種意向鎖

1)意向共享鎖(IS Lock),事務想要獲取一張表中的某幾行的共享鎖

2)意向排他鎖(IX Lock),事務想要獲得一張表中某幾行的排他鎖

IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容

從上表可以發現,X鎖與其他任何鎖都不兼容,而S鎖僅和S鎖兼容。最令人奇怪的是,意向鎖之間都兼容,那麼意向鎖設計的意思是什麼呢?

意向鎖的存在價值在於在定位到特定的行所持有的鎖之前,提供一種更粗粒度的鎖,可以大大節約引擎對於鎖的定位和處理的性能。因爲在存儲引擎內部,鎖是由一塊獨立的數據結構維護的,鎖的數量直接決定了內存的消耗和併發性能。例如,事務A對錶t的某些行修改(DML通常會產生X鎖),需要對t加上意向排它鎖,在A事務完成之前,B事務來一個全表操作(alter table等),此時直接在表級別的意向排它鎖就能告訴B需要等待(因爲t上有意向鎖),而不需要再去行級別判斷。

意向鎖是InnoDB自動加的,不需用戶干預。對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖(X);對於普通SELECT語句,InnoDB不會加任何鎖。
事務可以通過以下語句顯式給記錄集加共享鎖或排他鎖:

  • 共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
  • 排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE

InnoDB行鎖實現方式

InnoDB行鎖是通過給索引上的索引項加鎖來實現的。InnoDB這種行鎖實現特點意味着:只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!

創建一張表如下圖,id列創建索引,name列沒有創建索引

在這裏插入圖片描述

在這裏插入圖片描述

實驗一

session1 seesion2
start transaction start transaction
select * from test where name = ‘wy’ for update;
select * from test where name = ‘3’ for update;

在這裏插入圖片描述

可以看到session1,查詢的是name=‘wy’的數據,而session2查詢的是另外一行name=‘3’的數據,但是被阻塞住了,說明不加索引for update的查詢使用的是表鎖。

實驗二

session1 seesion2
start transaction start transaction
select * from test where id=1 for update;
select * from test where id =2 for update;

在這裏插入圖片描述

可以看到session1和session2使用的是行鎖,加鎖都成功了。

實驗三

給表插入數據如下
在這裏插入圖片描述

session1 seesion2
start transaction start transaction
select * from test where id=1 and name=‘wy’ for update;
select * from test where id =1 and name=‘wy1’for update;

在這裏插入圖片描述

可以看到session2阻塞住了,說明正在等待鎖資源。這是由於MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現鎖衝突的。

鎖的算法

Innodb存儲引擎有三種行鎖的算法,分別是:

  • Record Lock :單個行記錄上的鎖
  • Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄本身
  • Next-key Lock:Gap Lock+Record Lock,鎖定一個範圍,並且鎖定記錄本身

Next-key Lock

next-key的設計目的是爲了解決幻讀問題。利用這種鎖定技術,鎖定的不是單個值,而是一個範圍。然而當查詢的索引含有唯一屬性時,Innodb存儲引擎會對Next-key Lock進行優化,降級爲Record Lock,即僅鎖住索引本身,而不是範圍。

實驗一

1,創建一張表z,並插入如下數據,

create table z ( a int, b int, primary key(a),key(b))
在這裏插入圖片描述

2,表z的列b是輔助索引,若在會話A中執行下面的sql語句:

select * from z where b = 3 for update

由於有兩個索引,需要分別進行鎖定,對於聚集索引,其僅對列a等於5的索引加上Record Lock,而對於輔助索引,其加上的是Next-key Lock,鎖定的是(1,3),(3,6)。所以在新會話B中運行一下Sql語句,都會被阻塞。

在這裏插入圖片描述

實驗二

在Innodb存儲引擎中,對於Insert操作,其會檢查插入記錄的下一條記錄是否被鎖定,若已經被鎖定,則不允許查詢。

在這裏插入圖片描述

一致性非鎖定讀

一致性的非鎖定讀是指Innodb存儲引擎通過多版本控制的方式來讀取當前執行時間數據庫中的行數據。如果讀取的行正在執行delete或update操作,這時讀取操作不會因此去等待行上鎖的釋放。相反地,Innodb存儲引擎回去讀取行的一個快照數據。

快照數據通過undo段來完成。在innodb存儲引擎的默認設置下,默認讀取不會佔用和等待表上的鎖。一個行記錄可能不止有一個快照數據,一般我們稱這種技術爲行多版本技術。由此帶來的併發控制,稱爲多版本併發控制(MVVC)

在事務隔離級別RC和RR下,Innodb存儲引擎使用的是非鎖定的一致性讀。在RC隔離級別下,非一致性讀總是讀取被鎖定行的最新一份快照數據。而在RR隔離級別下,非一致性讀總是讀取事務開始的行數據版本。

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