mysql隱式鎖 innodB的隱式鎖

2021-10-17 17:15:15 字數 4048 閱讀 1047

一、知識準備之隱式鎖

innodb 實現了乙個延遲加鎖的機制,來減少加鎖的數量,在**中稱為隱式鎖(implicit lock)。隱式鎖中有個重要的元素,事務id(trx_id)。隱式鎖的邏輯過程如下:

a. innodb的每條記錄中都乙個隱含的trx_id欄位,這個字段存在於簇索引的b+tree中。

b. 在操作一條記錄前,首先根據記錄中的trx_id檢查該事務是否是活動的事務(未提交或回滾)。如果是活動的事務,首先將隱式鎖轉換為顯式鎖(就是為該事務新增乙個鎖)。

c. 檢查是否有鎖衝突,如果有衝突,建立鎖,並設定為waiting狀態。如果沒有衝突不加鎖,跳到e。

d. 等待加鎖成功,被喚醒,或者超時。

e. 寫資料,並將自己的trx_id寫入trx_id欄位。page lock可以保證操作的正確性。

二、具體**

**:《innodb smo & page extent & lock & latch》 by 何登成

innodb 的 insert 操作,對插入的記錄不加鎖,但是此時如果另乙個執行緒進行當前讀,類似與以下的用例,session 2 會鎖等待 session 1,那麼這是如何實現的呢?

session 1: session 2:

set autocommit = 『 off 』;

insert into c values (11, 』 aaa』);

select * from c where c1 = 11 lock in share mode;

下面是 session 2 的原始碼跟蹤流程:

row_search_for_mysql();

sel_set_rec_lock();

// 將記錄上的 implicit 鎖轉換為 explicit 鎖

lock_rec_convert_impl_to_expl();

// 查詢當前記錄上是否存在 implicit 鎖

// 1. 必須已經持有了 kernel mutex

// 2. 獲取記錄上的 db_trx_id 系統列,獲取事務 id

// 3. 根據事務 id,判斷當前事務是否為活躍事務

// 4. 若為活躍事務,則返回此活躍事務物件

impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);

ut_ad(mutex_own(&kernel_mutex));

trx_id = row_get_rec_trx_id();

trx_is_active(trx_id);

// 判斷返回事務,是否含有 explicit 鎖;若有,直接返回;否則將

// implicit 鎖轉化為 explicit 鎖;由 session 2 完成 session 1 insert 記錄的加鎖

lock_rec_has_expl(impl_trx);

// 當前 session 1 不存在 explicit 鎖,因此直接建立乙個鎖,鎖模式為

// lock_rec | lock_x | lock_rec_not_gap

// 由於 insert 記錄上不可能有其他鎖,因此轉化直接成功,x 鎖加上

lock_rec_add_to_queue();

// 完成 session 1 的 insert 操作的 implicit 到 explicit 鎖轉化之後,此時可以加 session 2

// 的 scan s 鎖,但是會等待 session 1 放鎖

lock_rec_lock();

備註:insert 不加鎖,或者說是 implicit lock 的意義其實十分重大。從前面介紹的 lock 結構中,我們可以分析出,其實 innodb 的乙個鎖結構的開銷是比較大的。 或者說innodb 鎖一條記錄的開銷,與鎖乙個頁面中所有記錄的開銷是一樣的。而 insert 通過 implicit 方式加鎖,極大的減輕了 insert 時的鎖模組開銷,對於 innodb 支援併發 insert 操作,是乙個極大的提公升。

三、隱式鎖的重要問題——check duplicate

**:《innodb smo & page extent & lock & latch》 by 何登成

進一步參考: innodb鎖系統 insert/delete 鎖處理及死鎖示例分析 

這裡主要看聚集索引的check duplicate。check duplicate也就是保證在隱式鎖情況下,多個事務的insert是如何保證索引的unique的。

1、聚集索引check duplicate

ha_innobase::write_row();

row_ins_index_entry_low();

// 做 search path,將 cursor 定位到第乙個小於等於插入值的位置

btr_cur_search_to_nth_level(page_cur_le);

// cursor 是 binary search 之後在葉節點定位的 insert 位置

// 判斷 binary search 的結果,當前記錄與待 insert 記錄有幾個相同的列

// 若相同列取值的列數量(cursor->low_match),超過當前索引的唯一鍵值數量,

// 則可能存在唯一性鍵值衝突

row_ins_duplicate_error_in_clust(cursor, entry, thr);

n_unique = dict_index_get_n_uniques();

if (cursor->low_match >= n_unique)

// 對 cursor 對應的已有記錄加 s 鎖(可能會等待),保證記錄上的操作,包括:

// insert/update/delete 已經提交或者回滾

// s 鎖已經可以保證其他事務的 insert 操作不能進行,因為在真正

// insert 操作進行時,會嘗試對 下乙個record加 x 鎖,詳見下一章節分析

row_ins_set_shared_rec_loc(lock_s);

lock_clust_rec_read_check_and_lock();

// 判斷 cursor 對應的記錄上是否存在 implicit 鎖(有活躍事務)

// 若存在,則將 implicit 鎖轉化為 explicit 鎖

lock_rec_convert_impl_to_expl();

lock_rec_lock(); //如果上面的隱式鎖轉化成功,此處加s鎖將會等待,直到活躍事務釋放鎖。

// s 鎖加鎖完成之後,可以再次做判斷,最終決定是否存在 unique 衝突

// 1. 判斷 insert 記錄與 cursor 對應的記錄取值是否相同

// 2. 二級唯一鍵值鎖引,可以存在多個 null 值

// 3. 最後判斷記錄的 delete_bit 狀態,判斷記錄是否被刪除提交

row_ins_dupl_err_with_rec();

cmp_dtuple_rec_with_match();

return !rec_get_deleted_flag();

注意:s鎖加鎖成功之時,活躍事務應當提交或回滾並釋放鎖;但不管是提交還是回滾,cursor指向的record仍然存在,可能會有delete標誌(發生回滾)。

2、輔助索引check duplicate

a、聚簇索引 primary key 是唯一的;非聚簇唯一索引,其索引也是唯一的。

b、若 insert 記錄與聚簇索引項完全相同,並且聚簇索引項為刪除項,則直接將其刪除標記設定為 0,並在刪除項上做 update。

c、若 insert 記錄與非聚簇唯一索引項鍵值完全相同, 並且非聚簇索引項為刪除項, 此時並不一定修改項狀態,還需要判斷兩者對應的 primary key 是否相同,若 primary key 也相同,則重用項;否則,插入新項。

d、聚簇索引中,相同 primary key 取值的項,最多只有一項,不可能存在多項。

e、非聚簇唯一索引,索引鍵值相同的項可能有多項,但是這些項,其 primary  key 是不同的;而且,這些項,只有乙個是有效項,其他項都為已刪除的提交項。

f、聚簇索引的唯一性檢查,只需要檢測 insert 對應的記錄即可,因為只有一項;非聚簇唯一索引的唯一性檢測,需要向後檢查多條鍵值相同記錄

mysql 隱式鎖和顯示鎖 MySQL的鎖機制

2 解鎖階段 當事務釋放了乙個封鎖以後,事務進入解鎖階段,在該階段只能進行解鎖操作不能再進行加鎖操作。5 隱式和顯示鎖定 innodb會根據隔離級別在需要的時候自動加鎖,這稱為隱式加鎖。另外,innodb也支援通過特定的語句進行顯示加鎖 顯示加共享鎖 select lock in share mod...

顯式鎖與隱式鎖的區別

解決的方法 格式描述 同步 塊 關鍵字 synchronized 鎖物件 隱式鎖,多個執行緒的鎖物件必須唯一 同步方法 修飾符 synchronized 返回型別 方法名 隱式鎖,誰呼叫該方法誰就是鎖物件 顯示鎖reentrantlock類的lock unlock 方法 顯式鎖,有程式設計師決定在那...

MySQL的InnoDB鎖機制

在innodb的事務隔離級別是可重複讀級別且innodb locks unsafe for binlog禁用的前提下,mysql的鎖機制經過測試為 1.當update和delete操作的時候,mysql的加鎖機制大概為三步 1 對where條件後面的條件進行鎖索引區域操作,如果沒有壓上索引,則整個索...