共計 2241 個字符,預計需要花費 6 分鐘才能閱讀完成。
本篇內容介紹了“MySQL 中 InnoDB 鎖機制分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
一 前言
本文介紹另外兩種鎖 Insert Intention Locks 和 AUTO-INC Locks
二 常見的鎖類型
2.1 根據鎖持有的時間粒度,分為
1. 內存級別:類似 mutex,很快釋放
2. 語句級別:statement 結束,釋放
3. 事務級別:transaction 提交或者回滾才釋放
4. 會話級別:session 級別,連接斷開才釋放
2.2 AUTO-INC lock
AUTO-INC lock 是一個特殊的表級鎖,當一個事務向含有自增字段的表插入數據時,該事務會獲取一個 AUTO-INC lock,其他事務必須等待直到已經獲取鎖的 insert 語句結束。因此, 多個并發事務不能同時獲取同一個表上面的 AUTO-INC lock, 如果持有 AUTO-INC 鎖太長時間可能會影響到數據庫性能 (比如 INSERT INTO t1… SELECT … FROM t2 這類語句) 或者死鎖.
鑒于 AUTO-INC 鎖的特性,MySQL 5.1.22 通過新增參數 innodb_autoinc_lock_mode 來控制自增序列的算法。該參數可以設置為 0,1,2.
在學習 innodb_autoinc_lock_mode 之前,我們先了解 insert 語句的類型
1 Simple inserts
能夠事先確定具體行數的 insert 語句,比如 insert into tab values()…(); replace 等等。INSERT … ON DUPLICATE KEY UPDATE 和還有子查詢的 insert 語句除外。
2 Bulk inserts
和 Simple inserts 對立,事先不能確定插入行數的 insert/replace 語句,insert … select ;replace …select; load data into table .. 這種情況下 Innodb 在執行具體的行的時候 會為每一行單獨分配一個 auto_increment 值。
3 Mixed-mode inserts
該情形是 Simple inserts 模式中,有些 insert 指定了 自增字段的具體值,有些沒有指定。比如:
INSERT INTO t1 (c1,c2) VALUES (1, a), (NULL, b), (5, c), (NULL, d
INSERT … ON DUPLICATE KEY UPDATE
接下來我們再看 MySQL 對 auto_increment 的優化模式。
innodb_autoinc_lock_mode=0,是傳統的方式。InnoDB 會在分配前給表加上 AUTO_INC 鎖,并在 SQL 結束時釋放掉。該模式保證了在 STATEMENT 復制模式下,備庫執行類似 INSERT … SELECT 這樣的語句時的一致性,因為這樣的語句在執行時無法確定到底有多少條記錄,只有在執行過程中不允許別的會話分配自增值,才能確保主備一致。
很顯然這種鎖模式非常影響并發插入的性能,但卻保證了一條 SQL 內自增值分配的連續性。
innodb_autoinc_lock_mode=1,這個是 InnoDB 的默認值。該模式下對于 Simple inserts,InnoDB 會先加一個 autoinc_mutex 鎖,然后去判斷表上是否有別的線程加了 LOCK_AUTO_INC 鎖,如果有的話,釋放 autoinc_mutex,并使用傳統的加鎖模式。否則,在預留本次插入需要的自增值之后,就快速的將 autoinc_mutex 釋放掉。很顯然,對于普通的并發 INSERT 操作,都是無需加 LOCK_AUTO_INC 鎖的。因此該模式提高了系統并發性;
innodb_autoinc_lock_mode=2,這種模式下只在分配時加個 mutex 即可,很快就釋放,不會像值為 1 那樣在某些場景下會退化到傳統模式。因此設為 2 不能保證批量插入的復制安全性。
2.3 Insert Intention Locks
插入意向鎖是 gap 鎖的一種,只是針對 insert。當并發事務多條 insert 插入同一個 GAP, 如果他們不是插入同一行記錄,會話之間并不會相互等待。例如索引記錄刪 有 12,17 兩個記錄,兩個會話同時插入記錄 13,15,他們會分別為 (12,17) 加上 GAP 鎖,但相互之間并不沖突(因為插入的記錄不沖突)。
當向某個數據頁中插入一條記錄時,總是會調用函數 lock_rec_insert_check_and_lock 進行鎖檢查(構建索引時的數據插入除外),會去檢查當前插入位置的下一條記錄上是否存在鎖對象,這里的下一條記錄不是指的物理連續,而是按照邏輯順序的下一條記錄。
如果下一條記錄上不存在鎖對象:若記錄是二級索引上的,先更新二級索引頁上的最大事務 ID 為當前事務的 ID;直接返回成功。
如果下一條記錄上存在鎖對象,就需要判斷該鎖對象是否鎖住了 GAP。如果 GAP 被鎖住了,并判定和插入意向 GAP 鎖沖突,當前操作就需要等待,加的鎖類型為 LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,并進入等待狀態。但是插入意向鎖之間并不互斥。這意味著在同一個 GAP 里可能有多個申請插入意向鎖的會話。
“MySQL 中 InnoDB 鎖機制分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!