MySQL之InnoDB鎖機制

InnoDB存儲引擎中的鎖

鎖的類型

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

  1. 共享鎖(S Lock):允許事務讀一行數據。
  2. 排他鎖(X Lock):允許事務刪除或更新一行數據。

如果一個事務 T1 已經獲得了行 r 的共享鎖,那麼另外的事務 T2 可以立即獲得行 r 的共享鎖,因爲讀取並沒有改變行 r 的數據,稱這種情況爲鎖兼容。但若有其他的事務 T3 想獲得行 r 的排他鎖,則其必須等待事務T1、T2釋放行 r 上的共享鎖這種情況稱爲鎖不兼容。即共享鎖不互斥獲取,排他鎖互斥獲取。

共享鎖與排他鎖的共存問題

接下來我們考慮這樣一個問題:
事務A鎖住了表中的一行,讓這一行只能讀,不能寫。之後,事務B申請整個表的寫鎖。如果事務B申請成功,那麼理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。數據庫需要避免這種衝突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。
爲了解決這個衝突,數據庫需要做兩個判斷:

  1. 判斷表是否已被其他事務用表鎖鎖表;
  2. 判斷表中的每一行是否已被行鎖鎖住。

由於第二個判斷條件效率低下,因此引入了意向鎖的機制。
意向鎖是爲了解決程序執行高效性問題,並不是爲了多併發下數據的一致性問題。

意向鎖

InnoDB 存儲引擎支持多粒度鎖定,這種鎖定允許事務在行級上的鎖和表級上的鎖同時存在。爲了支持在不同粒度上進行加鎖操作,InnoDB 存儲引擎支持一種額外的鎖方式,稱之爲意向鎖。意向鎖是將鎖定的對象分爲多個層次,意向鎖意味着事務希望在更細粒度上進行加鎖。
意向鎖分爲兩種:

  1. 意向共享鎖(IS Lock):事務想要獲得一張表中某幾行的共享鎖;
  2. 意向排他鎖(IX Lock):事務想要獲得- -張表中某幾行的排他鎖。

首先讓我們看看數據庫數據存儲結構的層次圖:
在這裏插入圖片描述
有了意向鎖後,考慮1.2中我們所說的情況,事務A必須先申請表的意向共享鎖,成功後再申請一行的行鎖。此時,如果事務B要申請整個表的寫鎖,判斷條件就變成如下兩個條件:

  1. 判斷表是否已被其他事務用表鎖鎖表(不變);
  2. 發現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務B申請表的寫鎖會被阻塞。

注意:意向鎖(IX,IS)是表級鎖,不會和行級的排他鎖(X)或 共享鎖(S)發生衝突。只會和表級的鎖(X,S)發生衝突; 行級別的X和S按照普通的共享、排他規則即可。只要寫操作不是同一行,就不會發生衝突。

多版本併發控制(MVCC)

數據庫在針對多併發問題,提出了多版本控制的概念;核心原理是:

  1. 寫任務發生時,將數據克隆一份,以版本號區分;
  2. 寫任務操作新克隆的數據,直至提交;
  3. 併發讀任務可以繼續讀取舊版本的數據,不至於阻塞;

在這裏插入圖片描述
如上圖所示:

  1. 最開始數據的版本是V0;
  2. T1時刻發起了一個寫任務,這是把數據clone了一份,進行修改,版本變爲V1,但任務還未完成;
  3. T2時刻併發了一個讀任務,依然可以讀V0版本的數據;
  4. T3時刻又併發了一個讀任務,依然不會阻塞;

可以看到,數據多版本,通過“讀取舊版本數據”能夠極大提高任務的併發度。

一致性鎖定讀

此外,某些情況下,我們需要顯式地對數據庫讀取操作,進行加鎖以保證數據邏輯的一致性,這要求數據庫支持加鎖語句,
持加鎖語句,即使是對於SELECT的只讀操作。InnoDB存儲引擎對於SELECT語句支
持兩種一致性的鎖定讀 (locking read)操作:
1. SELECT … FOR UPDATE
2. SELECT … LOCK IN SHARE MODE



SELECT…FOR UPDATE對讀取的行記錄加一個X鎖,其他事務不能對已鎖定的行加上任何鎖。SELECT…LOCK IN SHARE MODE對讀取的行記錄加一個S鎖,其他事務可以向被鎖定的行加S鎖,但是如果加X鎖,則會被阻塞。
對於一-致性非鎖定讀,即使讀取的行已被執行了SELECT…FOR UPDATE,也是可以進行讀取的,這和之前討論的情況一樣。此外,SELECT…FOR UPDATE, SELECT…LOCK IN SHARE MODE必須在一個事務中,當事務提交了,鎖也就釋放了。因此在使用.上述兩句SELECT鎖定語句時,務必加上BEGIN, START TRANSACTION或者SET AUTOCOMMIT=0。

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