MySql InnoDB鎖類型

MySql InnoDB鎖類型

從類型上來分類,InnoDB存儲引擎實現了兩種標準的鎖

  • 共享鎖(S-Lock):允許事務讀一行數據
  • 排它鎖(X-Lock):允許事務刪除或者更新一行數據

如果一個事務獲取了S鎖,那麼其他事務也可以立即獲得S鎖,但如果要對記錄加X鎖,必須等待該記錄的所有鎖(S或X)釋放後才能加成功。如下表所示為S和X鎖的兼容性

MySql InnoDB鎖類型

X鎖和S鎖兼容性

MySql支持多粒度的鎖定操作,這就允許事務在表級和行級上的鎖同時存在。為了支持在不同粒度上的加鎖操作,InnoDB支持了額外的一種鎖,意向鎖(Intention Lock)。意向鎖是將鎖定的對象分為多個層級,意味著事務希望在更細粒度上進行加鎖。

下邊是一個網友介紹的意向鎖的作用:

innodb的意向鎖有什麼作用?
mysql官網上對於意向鎖的解釋中有這麼一句話
“The main purpose of IX and IS locks is to show that someone is locking a row, or going to lock a row in the table.”
意思是說加意向鎖的目的是為了表明某個事務正在鎖定一行或者將要鎖定一行。
那麼,意向鎖的作用就是“表明”加鎖的意圖,可是為什麼要表明這個 意圖呢?
如果僅僅鎖定一行僅僅需要加一個鎖,那麼就直接加鎖就好了,這裡要表明加鎖意圖的原因是因為要鎖定一行不僅僅是要加一個鎖,而是要做一系列操作嗎?

作者:尹發條地精

我最近也在看這個,我說一下我的理解
①在mysql中有表鎖,LOCK TABLE my_tabl_name READ; 用讀鎖鎖表,會阻塞其他事務修改表數據。LOCK TABLE my_table_name WRITe; 用寫鎖鎖表,會阻塞其他事務讀和寫。

②Innodb引擎又支持行鎖,行鎖分為共享鎖,一個事務對一行的共享只讀鎖。排它鎖,一個事務對一行的排他讀寫鎖。
③這兩中類型的鎖共存的問題考慮這個例子:
事務A鎖住了表中的一行,讓這一行只能讀,不能寫。之後,事務B申請整個表的寫鎖。如果事務B申請成功,那麼理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。
數據庫需要避免這種衝突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。

數據庫要怎麼判斷這個衝突呢?
step1:判斷表是否已被其他事務用表鎖鎖表
step2:判斷表中的每一行是否已被行鎖鎖住。
注意step2,這樣的判斷方法效率實在不高,因為需要遍歷整個表。
於是就有了意向鎖。在意向鎖存在的情況下,事務A必須先申請表的意向共享鎖,成功後再申請一行的行鎖。在意向鎖存在的情況下,
上面的判斷可以改成
step1:不變
step2:發現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務B申請表的寫鎖會被阻塞。

注意:申請意向鎖的動作是數據庫完成的,就是說,事務A申請一行的行鎖的時候,數據庫會自動先開始申請表的意向鎖,不需要我們程序員使用代碼來申請。

總結:為了實現多粒度鎖機制(白話:為了表鎖和行鎖都能用)

意向鎖分類:

  • 意向共享鎖(IS):事務想要獲取一張表中某幾行的共享鎖
  • 意向排它鎖(IX):事務想要獲取一張表中的某幾行的排它鎖

意向鎖的兼容性:

MySql InnoDB鎖類型

意向鎖兼容性

一致性非鎖定讀

一致性非鎖定讀是指InnoDB存儲引擎通過多版本控制的方式來讀取當前執行時間數據庫中行的數據。如果讀取的行正在執行DELETE或者UPDATE操作,這時讀取操作並不會因此等待該行的X鎖釋放,而是讀取一個快照數據。

MySql InnoDB鎖類型

當然在不同的事務隔離級別下,非一致鎖定讀讀取的快照順序也是不一樣的。

  • READ COMMITTED:讀取的快照數據永遠是最新的一份快照數據
  • READ REPEATABLE:讀取的快照是當前事務開始時的快照數據

一致性鎖定讀:

在數據庫隔離級別為RR級別下,select操作使用了一致性非鎖定讀。在某些情況下,用戶需要顯示地對讀操作進行加鎖以保證數據的一致性邏輯。一般來說會使用以下兩種方式:

  • select … for update
  • select … lock in share model

其中select … for update會給選擇的行加一個X鎖,select … lock in share model會加一個S鎖。並且這兩種用法必須在一個事務中。當事務提交後鎖也就釋放了。

鎖的算法

InnoDB有3中鎖的算法

  • Record Lock:在單行上加鎖
  • Gap Lock:間隙鎖,鎖定一個範圍,但不包含當前記錄
  • Next-Key Lock:Gap Lock+Record Lock,鎖定一個範圍,幷包含當前記錄。

對於Next-Key Lock,其解決的是數據庫的幻象問題,對於一個索引包含10,11,13,20的數據,那麼Next-Key Lock可以鎖定的區間為:

(-無窮,10],(10,11],(11, 13],(13, 20],(20, +無窮)

當查詢的索引含有唯一屬性時,InnoDB會對Next-Key Lock進行優化,將其降級為Record Key,只是鎖住索引本身,並不會鎖範圍。

MySql InnoDB鎖類型

鎖降級

但對於非聚集索引,則會在非聚集索引上加Next-Key Lock

MySql InnoDB鎖類型

對於select * from z where b = 3,則會在(1, 3]上加鎖,同時會在該記錄後邊加一個gap lock,即(3, 6),如果執行以下兩個語句都會造成堵塞。

由此可見gap 鎖是為了解決數據庫的幻讀現象。

對於唯一鍵的鎖定,Next-Key Lock會降級為Record Lock的前提僅限於查詢所有的唯一索引列。若唯一索引有多個列組成,而查詢的是多個索引中的一個,那麼查詢仍然是range查詢,而不是point查詢,仍然使用Next-Key Lock進行鎖定。

幻讀問題

MySql InnoDB鎖類型

上圖所示為幻讀現象,A在同一個事務中讀取的數據不一致,gap lock則解決了這個問題。在RR隔離級別下,gap鎖會為(2, 無窮)加X鎖,這樣會話B插入4時就會阻塞。

鎖存在的問題

髒讀

MySql InnoDB鎖類型

在READ uncommitted隔離級別下,事務B可以讀取A未提交的數據,如果A rollback,則B兩次讀取的數據將不一致。而在READ Committed隔離級別下,事務讀取的是記錄最新提交的快照,因此可以避免髒讀現象

幻讀

在READ Committed隔離級別下,當使用範圍查詢時會出現兩次讀取的數據不一致,因此造成幻讀現象,在READ REPEATABLE級別下,由於Gap鎖的作用可以避免幻讀。


分享到:


相關文章: