切換語言為:簡體
MySql中這五種情況不加GAP鎖,只加行鎖

MySql中這五種情況不加GAP鎖,只加行鎖

  • 爱糖宝
  • 2024-08-26
  • 2048
  • 0
  • 0

在原始碼中有這麼一段:

MySql中這五種情況不加GAP鎖,只加行鎖

goto no_gap_lock表示加的鎖型別為:LOCK_REC_NOT_GAP,也就是我們通常所理解的行鎖,只鎖記錄行本身,不說記錄前面的間隙。

上面程式碼中,如果進入else分支,那麼鎖的型別是LOCK_ORDINARY,它表示既鎖記錄本身,也鎖記錄前面的間隙,也就是我們常說的next-key鎖,因此大家能猜到,那有沒有一種鎖型別只鎖記錄前面的間隙而不鎖記錄本身呢,當然有啦,那就是LOCK_GAP,對應原始碼為:

MySql中這五種情況不加GAP鎖,只加行鎖

扯遠了,我們還是回答本文的主題:什麼時候不加GAP鎖,只加行鎖?

第一種情況

再看看前面的原始碼:

MySql中這五種情況不加GAP鎖,只加行鎖

因此,只要符合if條件,進入no_gap_lock流程就是我們要的答案,由於if中都是或條件,因此我們只需要一個個條件進行分析就能得到答案。

首先,set_also_gap_locks為false,在原始碼中set_also_gap_locks預設為true,只在一個地方進行了賦值,賦值程式碼為:

MySql中這五種情況不加GAP鎖,只加行鎖

第三個條件不用管,其他條件為:

  1. trx->isolation_level <= TRX_ISO_READ_COMMITTED:表示隔離級別是讀未提交或讀已提交

  2. prebuilt->select_lock_type != LOCK_NONE:表示當前SQL需要加鎖

  3. thd_is_select(trx->mysql_thd)):當前SQL是select查詢

其實很好理解,首先當前SQL得是查詢並且想要加鎖,也就是SELECT ... FOR UPDATE和 SELECT... LOCK IN SHARE MODE兩種情況,但是如果隔離級別是讀未提交或讀已提交,那麼就不需要加GAP鎖。

反過來理解就是如果當前SQL是查詢並且想要加鎖,但是如果隔離級別是可重複讀或序列讀,才需要加GAP鎖。

因此,我們要理解GAP鎖的作用是什麼,GAP鎖的作用就是:在一個事務中多次查詢得到的結果得是一樣的,特別是兩次查詢之間其他事務插入了新記錄,第二次查詢的時候也不能把新記錄查出來,對應的隔離級別就是可重複讀和序列讀,所以當隔離級別是讀未提交和讀已提交時不需要加GAP鎖。

第二種情況

MySql中這五種情況不加GAP鎖,只加行鎖

srv_locks_unsafe_for_binlog是用在主從複製過程中的,這塊暫時還沒研究,AI給的答案是:

當 srv_locks_unsafe_for_binlog 引數設定為 ON 時,InnoDB 儲存引擎會使用一種不太安全的鎖定策略,這種策略可能會導致某些事務在從庫上執行時產生不同的結果。這種鎖定策略可能會提高效能,因為它減少了鎖定等待時間,但可能會導致複製問題。 相反,當 srv_locks_unsafe_for_binlog 引數設定為 OFF(預設值)時,InnoDB 儲存引擎會使用更安全的鎖定策略,以確保事務的可重複性,從而保證在複製環境中資料的一致性。這種策略可能會降低效能,因為它可能會增加鎖定等待時間,但可以確保主從資料的一致性。 在大多數情況下,特別是在生產環境中,應該將 srv_locks_unsafe_for_binlog 設定為 OFF,以確保資料的一致性和事務的完整性。只有在非常特殊的情況下,並且對可能產生的複製問題有充分的瞭解和接受時,才應該考慮將其設定為 ON

第三種情況

第三個條件是trx->isolation_level <= TRX_ISO_READ_COMMITTED,和前面set_also_gap_locks的判斷類似,對於隔離級別是讀未提交或讀已提交則不需要加GAP鎖。

第四種情況

第四個條件為(unique_search && !rec_get_deleted_flag(rec, comp))

  • unique_search表示當前查詢是唯一搜索,表示只會搜尋出一條記錄

  • !rec_get_deleted_flag(rec, comp)表示搜尋出來的記錄delete mark為false,表示記錄沒有被刪除,實際上InnoDB中的刪除記錄只是將delete mark設定為true

也就是說,當前SQL已經查到了一條記錄,並且可以判斷出當前SQL只有可能查出一條資料,那麼就不需要對查出來的記錄加GAP鎖了,因為只有可能查出一條記錄,因此這裏的重點是:什麼是unique_search?

如何理解unique_search?

上程式碼:

MySql中這五種情況不加GAP鎖,只加行鎖

  1. match_mode == ROW_SEL_EXACT:當前查詢是等值查詢

  2. dict_index_is_unique(index):當前索引是唯一索引

  3. dtuple_get_n_fields(search_tuple) == dict_index_get_n_unique(index):查詢條件能覆蓋索引的全部欄位,比如a,b,c組成的聯合唯一索引,那麼查詢條件中必須包含a,b,c三個欄位

  4. (dict_index_is_clust(index) || !dtuple_contains_null(search_tuple)):以上三條件還不足以保證只會查出一條資料,因為唯一索引有可能允許欄位為null,因此要麼索引是聚集索引(欄位不能為NULL),或者查詢條件中不包含等於null的查詢(只針對索引的欄位)

以上四個條件全部成立就表示本次查詢是unique_search。

當然還需要注意,就算是unique_search,如果當前SQL沒有查詢到記錄,比如表裏只有id=1、id=2、id=3三條記錄,此時查詢id=4,那麼此時是會加GAP鎖的,準確一點加的是LOCK_ORDINARY鎖,也就是next-key鎖。

MySql中這五種情況不加GAP鎖,只加行鎖

那是給哪條記錄加的鎖呢:

MySql中這五種情況不加GAP鎖,只加行鎖

頁裡面的最大記錄,鎖最大記錄之前的間隙,這樣就不會允許其他事務插入id=4的記錄了。

第五種情況

dict_index_is_spatial(index),表示當前索引是空間索引,不需要管。


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.