MySQL 是怎么加行級鎖的?為什么一會是 next-key 鎖,一會是間隙鎖,一會又是記錄鎖?

大家好,我是小林 。
是不是很多人都對 MySQL 加行級鎖的規則搞的迷迷糊糊 , 一會是 next-key 鎖,一會是間隙鎖 , 一會又是記錄鎖 。
坦白說 , 確實還挺復雜的 , 但是好在我找點了點規律,也知道如何如何用命令分析加了什么類型的行級鎖 。
之前我寫過一篇關于「MySQL 是怎么加行級鎖的?」的文章,隨著我寫 MySQL 鎖相關的文章越來越多時,后來發現當時的文章寫的不夠詳細 。
為了讓大家很清楚的知道 MySQL 是怎么加行級鎖的 , 以及如何用命令分析加了什么行級鎖,所以我重寫了這篇文章 。
文章內容比較長,大家可以耐心看下去,一定會有新的發現!
什么 SQL 語句會加行級鎖?InnoDB 引擎是支持行級鎖的,而 MyISAM 引擎并不支持行級鎖 , 所以后面的內容都是基于 InnoDB 引擎 的 。
普通的 select 語句是不會對記錄加鎖的,因為它屬于快照讀,是通過 MVCC(多版本并發控制)實現的 。
如果要在查詢時對記錄加行級鎖,可以使用下面這兩個方式,這兩種查詢會加鎖的語句稱為鎖定讀 。
//對讀取的記錄加共享鎖(S型鎖)select ... lock in share mode;//對讀取的記錄加獨占鎖(X型鎖)select ... for update;上面這兩條語句必須在一個事務中,因為當事務提交了,鎖就會被釋放,所以在使用這兩條語句的時候 , 要加上 begin 或者 start transaction 開啟事務的語句 。
**除了上面這兩條鎖定讀語句會加行級鎖之外,update 和 delete 操作都會加行級鎖,且鎖的類型都是獨占鎖(X型鎖)** 。
//對操作的記錄加獨占鎖(X型鎖)updaet table .... where id = 1;//對操作的記錄加獨占鎖(X型鎖)delete from table where id = 1;共享鎖(S鎖)滿足讀讀共享,讀寫互斥 。獨占鎖(X鎖)滿足寫寫互斥、讀寫互斥 。

MySQL 是怎么加行級鎖的?為什么一會是 next-key 鎖,一會是間隙鎖,一會又是記錄鎖?

文章插圖
行級鎖有哪些種類?不同隔離級別下 , 行級鎖的種類是不同的 。
在讀已提交隔離級別下,行級鎖的種類只有記錄鎖 , 也就是僅僅把一條記錄鎖上 。
在可重復讀隔離級別下,行級鎖的種類除了有記錄鎖,還有間隙鎖(目的是為了避免幻讀),所以行級鎖的種類主要有三類:
  • Record Lock,記錄鎖 , 也就是僅僅把一條記錄鎖上;
  • Gap Lock,間隙鎖,鎖定一個范圍 , 但是不包含記錄本身;
  • Next-Key Lock:Record Lock + Gap Lock 的組合,鎖定一個范圍,并且鎖定記錄本身 。
接下來 , 分別介紹這三種行級鎖 。
Record LockRecord Lock 稱為記錄鎖,鎖住的是一條記錄 。而且記錄鎖是有 S 鎖和 X 鎖之分的:
  • 當一個事務對一條記錄加了 S 型記錄鎖后,其他事務也可以繼續對該記錄加 S 型記錄鎖(S 型與 S 鎖兼容),但是不可以對該記錄加 X 型記錄鎖(S 型與 X 鎖不兼容);
  • 當一個事務對一條記錄加了 X 型記錄鎖后,其他事務既不可以對該記錄加 S 型記錄鎖(S 型與 X 鎖不兼容),也不可以對該記錄加 X 型記錄鎖(X 型與 X 鎖不兼容) 。
舉個例子 , 當一個事務執行了下面這條語句:
mysql > begin;mysql > select * from t_test where id = 1 for update;事務會對表中主鍵 id = 1 的這條記錄加上 X 型的記錄鎖,這樣其他事務就無法對這條記錄進行修改和刪除了 。
MySQL 是怎么加行級鎖的?為什么一會是 next-key 鎖,一會是間隙鎖,一會又是記錄鎖?

文章插圖
img
當事務執行 commit 后,事務過程中生成的鎖都會被釋放 。
Gap LockGap Lock 稱為間隙鎖,只存在于可重復讀隔離級別 , 目的是為了解決可重復讀隔離級別下幻讀的現象 。
假設,表中有一個范圍 id 為(3,5)間隙鎖,那么其他事務就無法插入 id = 4 這條記錄了,這樣就有效的防止幻讀現象的發生 。
MySQL 是怎么加行級鎖的?為什么一會是 next-key 鎖,一會是間隙鎖,一會又是記錄鎖?

文章插圖
img
間隙鎖雖然存在 X 型間隙鎖和 S 型間隙鎖,但是并沒有什么區別,間隙鎖之間是兼容的,即兩個事務可以同時持有包含共同間隙范圍的間隙鎖,并不存在互斥關系,因為間隙鎖的目的是防止插入幻影記錄而提出的 。
Next-Key LockNext-Key Lock 稱為臨鍵鎖,是 Record Lock + Gap Lock 的組合,鎖定一個范圍,并且鎖定記錄本身 。

推薦閱讀