MySQL Innodb 中的鎖
MySQL Innodb 中的鎖
鎖是用來解決並發沖突的必要手段,MySQL 中的並發主要是指多個線程同時對同一個數據庫進行操作,其中不同線程可能代表不同的事務,本質上也就是對共享資源的不同事務的同時訪問。
Innodb 支持行級鎖和意向鎖。行級鎖就是對行記錄進行加鎖,行級鎖也分為兩種類型,一種是共享鎖( S 鎖),一種是排他鎖( X 鎖)。意向鎖為表級別的鎖,也就是將鎖定的對象分為多個層次,意向鎖意味著事務希望在更細粒度上進行加鎖,一般來說,意向鎖是從上往下(數據庫->表->頁->記錄)進行加鎖,其中任何一個部分導致等待,那麽該操作都會需要等待粗粒度的鎖的完成。
讀的鎖定操作
一致性非鎖定讀
MySQL 的默認事務隔離級別是 Repeatable Read,在事務隔離為 Repeatable Read 和 Read Committed 級別下,默認的讀取方式即為一致性非鎖定讀。一致性非鎖定讀即為在訪問行記錄時,不需要等待該行上的 X 鎖釋放。Innodb 的一致性非鎖定讀是以多版本控制實現的,在多版本控制中,會保存修改之前數據的快照,作為恢復使用。
需要註意的是:在 Repeatable Read 和 Read Committed 的兩種級別下的一致性非鎖定讀也是不同的,Repeatable Read 隔離級別下,總是讀取事務開始時的行數據,而 Read Committed 模式下總是讀取該行版本上的最新快照。
一致性鎖定讀
默認情況下,在 Repeatable Read 和 Read Committed 隔離界別下,SELECT 語句對一行的讀取是使用一致性非鎖定讀的,用戶可以通過指定 SELECT 語句使用一致性鎖定讀,例如:
- SELECT ... FOR UPDATE
- SELECT ... LOCK IN SHARE MODE
這兩種方法可以分別給行記錄加上一個 X 鎖和 S 鎖。
外鍵和鎖
對於一個外鍵的更新和插入,首先需要查詢父表中的記錄,即主動對父表加一個 S 鎖,這裏必須使用一致性鎖定讀。如果不這麽做,當另外事務 A 對父表的行記錄進行了刪除操作,而事務 B 打算在子表中添加一行與父表具有外鍵關系的行,事務 B 會讀到存在該外鍵,從而添加(從快照中讀取),但是實際上當事務 A 提交後,父表中將不存在該主鍵,從而導致父子表中完整性被破壞。
行鎖的三種方法
Record Lock:單個行記錄上的鎖。
Gap Lock:間隙鎖,不包含記錄本身。
Next-Key Lock:鎖定一個範圍同時也鎖定記錄本身。
在查詢的列是唯一索引時,Next-Key Lock 會降級為 Record Lock,以提高並發效率。
在 Repeatable Read 和 Read Committed 情況下使用行鎖的方法不同,在 Repeatable Read 下,使用 Next-Key Lock,而在 Read Committed 情況下,使用 Record Lock。
MySQL Innodb 中的鎖