自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 加鎖機制驗證記錄

數(shù)據(jù)庫 MySQL
MySQL 官方文檔 給出了不同類型語句的加鎖情形,但我覺得 這個總結(jié) 更到位,因此想結(jié)合文章的幾種情形,結(jié)合 InnoDB Monitor Output 做分析。文章是驗證過程的記錄,全文比較長,建議結(jié)合目錄查看感興趣的部分。

MySQL 官方文檔 給出了不同類型語句的加鎖情形,但我覺得 這個總結(jié) 更到位,因此想結(jié)合文章的幾種情形,結(jié)合 InnoDB Monitor Output 做分析。

文章是驗證過程的記錄,全文比較長,建議結(jié)合目錄查看感興趣的部分。

開啟 InnoDB Monitor

參考: 官方文檔

 

  1. SET GLOBAL innodb_status_output=ON-- 開啟輸出  
  2. SET GLOBAL innodb_status_output_locks=ON-- 開啟鎖信息輸出 

注意這些選項在 mysql 重啟后會恢復(fù)默認值。接下來使用命令查看信息:

  1. SHOW ENGINE INNODB STATUS\G 

樣例輸出,我們只關(guān)心鎖相關(guān)的內(nèi)容:

 

  1. ---TRANSACTION 929632, ACTIVE 27 sec 
  2. 2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9179 localhost root 
  4. TABLE LOCK table `test`.`id_pk_rc` trx id 929632 lock mode IX 
  5. RECORD LOCKS space id 1813 page no 3 n bits 72 index PRIMARY of table `test`.`id_pk_rc` trx id 929632 lock_mode X locks rec but not gap 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 
  7.  0: len 4; hex 80000005; asc     ;; 
  8.  1: len 6; hex 0000000e2f60; asc     /`;; 
  9.  2: len 7; hex 4c000002222e83; asc L   ". ;; 
  10.  3: len 1; hex 63; asc c;; 
  • “page no 3 n bits 72” 代表在第 3 頁的記錄上,lock bitmap 共 72 位
  • “index PRIMARY of …” 代表鎖在某個索引上,PRIMARY 代表鎖在主鍵上
  • “lock_mode X” 鎖模式,X 代表互斥,鎖模式可以參數(shù)官方文檔 InnoDB Locking
  • “locks rec but not gap” 代表記錄鎖,“locks gap before rec” 代表間隙鎖,沒有說明則代表 Next Key Lock
  • “heap no 4” 代表記錄的序號,0 代表 infimum 記錄、1 代表 supremum 記錄,用戶記錄從 2 開始
  • PHYSICAL RECORD 后面的內(nèi)容是索引記錄的內(nèi)存結(jié)構(gòu),通常沒辦法直接閱讀

這個記錄里沒法直接看出鎖住了哪些記錄。一種方法是通過 select * from information_schema.innodb_locks \G; 查看搶鎖沒搶到的信息,為了查看記錄,在測試時可以另開一個會話,用諸如 SELECT * FROM ... WHERE ... FOR UPDATE 來搶鎖,這樣就可以看出鎖在哪個記錄上了。樣例輸出:

 

  1. lock_id     | 929771:1817:4:4 
  2. lock_trx_id | 929771 
  3. lock_mode   | X 
  4. lock_type   | RECORD 
  5. lock_table  | `test`.`id_si_rc` 
  6. lock_index  | id_si 
  7. lock_space  | 1817 
  8. lock_page   | 4 
  9. lock_rec    | 4 
  10. lock_data   | 5, 3 -- 注意這里是數(shù)據(jù)標識 

還有一個工具好用的工具 innodb_ruby 可以用來解析 MySQL 的靜態(tài)文件。Monitor 日志里我們知道是哪個頁的哪條記錄,可以使用innodb_ruby 來找到對應(yīng)的記錄。(不過不建議在生產(chǎn)上使用)

不同情形下加鎖驗證

我們會考查 DELETE FROM t1 WHERE id = 5 語句在不同情形下的加鎖情況,通過構(gòu)造數(shù)據(jù)、執(zhí)行語句、查看 Monitor 日志來驗證加鎖的機制。

主鍵 + RC

結(jié)論:只對 ID = 5 這條記錄加 Record Lock

 

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_pk_rc(id int primary keyname varchar(32)); 
  3.  
  4. -- 準備數(shù)據(jù) 
  5. INSERT INTO id_pk_rc values(1, 'a'); 
  6. INSERT INTO id_pk_rc values(3, 'b'); 
  7. INSERT INTO id_pk_rc values(5, 'c'); 
  8. INSERT INTO id_pk_rc values(7, 'c'); 
  9. INSERT INTO id_pk_rc values(9, 'b'); 

執(zhí)行語句

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_pk_rc WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志:

 

  1. ---TRANSACTION 929632, ACTIVE 27 sec 
  2. 2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9179 localhost root 
  4. TABLE LOCK table `test`.`id_pk_rc` trx id 929632 lock mode IX 
  5. RECORD LOCKS space id 1813 page no 3 n bits 72 index PRIMARY of table `test`.`id_pk_rc` trx id 929632 lock_mode X locks rec but not gap 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 
  7.  0: len 4; hex 80000005; asc     ;; 
  8.  1: len 6; hex 0000000e2f60; asc     /`;; 
  9.  2: len 7; hex 4c000002222e83; asc L   ". ;; 
  10.  3: len 1; hex 63; asc c;; 

看到輸出里有 lock_mode X locks rec but not gap ,可以確定持有的是記錄鎖。

唯一索引 + RC

結(jié)論:索引和聚簇索引/主鍵中都對 ID = 5 加 Record Lock

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_ui_rc(pk int primary key, id intname varchar(32)); 
  3. CREATE UNIQUE INDEX id_ui ON id_ui_rc(id); 
  4.  
  5. -- 準備數(shù)據(jù) 
  6. INSERT INTO id_ui_rc values(1, 1, 'a'); 
  7. INSERT INTO id_ui_rc values(2, 3, 'b'); 
  8. INSERT INTO id_ui_rc values(3, 5, 'c'); 
  9. INSERT INTO id_ui_rc values(4, 7, 'c'); 
  10. INSERT INTO id_ui_rc values(5, 9, 'b'); 

執(zhí)行語句:

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_ui_rc WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志:

 

  1. ---TRANSACTION 929694, ACTIVE 6 sec 
  2. 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9241 localhost root 
  4. TABLE LOCK table `test`.`id_ui_rc` trx id 929694 lock mode IX 
  5. RECORD LOCKS space id 1815 page no 4 n bits 72 index id_ui of table `test`.`id_ui_rc` trx id 929694 lock_mode X locks rec but not gap 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
  7.  0: len 4; hex 80000005; asc     ;; 
  8.  1: len 4; hex 80000003; asc     ;; 
  9.  
  10. RECORD LOCKS space id 1815 page no 3 n bits 72 index PRIMARY of table `test`.`id_ui_rc` trx id 929694 lock_mode X locks rec but not gap 
  11. Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  12.  0: len 4; hex 80000003; asc     ;; 
  13.  1: len 6; hex 0000000e2f9e; asc     / ;; 
  14.  2: len 7; hex 7a0000059525c9; asc z    % ;; 
  15.  3: len 4; hex 80000005; asc     ;; 
  16.  4: len 1; hex 63; asc c;; 

可以看到分別對 index id_ui 和 index PRIMARY 加了 Record Lock。

非唯一索引 + RC

結(jié)論:會對所有 ID = 5 的索引記錄加 Record Lock,同時對主鍵加 Record Lock。

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_si_rc(pk int primary key, id intname varchar(32)); 
  3. CREATE INDEX id_si ON id_si_rc(id); 
  4.  
  5. -- 準備數(shù)據(jù) 
  6. INSERT INTO id_si_rc values(1, 1, 'a'); 
  7. INSERT INTO id_si_rc values(2, 3, 'b'); 
  8. INSERT INTO id_si_rc values(3, 5, 'c'); 
  9. INSERT INTO id_si_rc values(4, 7, 'c'); 
  10. INSERT INTO id_si_rc values(5, 5, 'b'); 

執(zhí)行語句:

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_si_rc WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志(省略了 PHYSICAL RECORD 的內(nèi)容):

 

  1. ---TRANSACTION 929779, ACTIVE 3 sec 
  2. 3 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9325 localhost root 
  4. TABLE LOCK table `test`.`id_si_rc` trx id 929779 lock mode IX 
  5. RECORD LOCKS space id 1817 page no 4 n bits 72 index id_si of table `test`.`id_si_rc` trx id 929779 lock_mode X locks rec but not gap 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
  7.  ... 
  8. Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
  9.  ... 
  10.  
  11. RECORD LOCKS space id 1817 page no 3 n bits 72 index PRIMARY of table `test`.`id_si_rc` trx id 929779 lock_mode X locks rec but not gap 
  12. Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  13.  ... 
  14. Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  15.  ... 

可以看到一共有 4 條記錄,首先可以看到索引 id_si 和 PRIMARY 分別鎖住了兩條記錄,加的鎖都是 X Record Lock No Gap,也就是記錄鎖。我們通過 select * from information_schema.innodb_locks \G; 查看是鎖住了 3, 5 這兩條記錄。

 

  1. lock_id     | 929779:1817:4:4 
  2. lock_trx_id | 929779 
  3. lock_mode   | X 
  4. lock_type   | RECORD 
  5. lock_table  | `test`.`id_si_rc` 
  6. lock_index  | id_si 
  7. lock_space  | 1817 
  8. lock_page   | 4 
  9. lock_rec    | 4 
  10. lock_data   | 5, 3  <- 注意這里 

無索引 + RC

結(jié)論:對所有記錄加 Record Lock 再釋放不匹配的記錄鎖

這個情形比較特殊,涉及兩個 知識點

  1. MySQL 加鎖時是對處理過程中“掃描”到的記錄加鎖,不管這條記錄最終是不是通過 WHERE 語句剔除了
  2. 對于 READ COMMITTED,MySQL 在掃描結(jié)束后,會違反 #1,釋放 WHERE 條件不滿足的記錄鎖

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_ni_rc(pk int primary key, id intname varchar(32)); 
  3.  
  4. -- 準備數(shù)據(jù) 
  5. INSERT INTO id_ni_rc values(1, 1, 'a'); 
  6. INSERT INTO id_ni_rc values(2, 3, 'b'); 
  7. INSERT INTO id_ni_rc values(3, 5, 'c'); 
  8. INSERT INTO id_ni_rc values(4, 7, 'c'); 
  9. INSERT INTO id_ni_rc values(5, 5, 'b'); 

執(zhí)行語句:

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_ni_rc WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志(省略了 PHYSICAL RECORD 的內(nèi)容):

 

  1. ---TRANSACTION 1446, ACTIVE 17 sec 
  2. 2 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2 
  3. MySQL thread id 7, OS thread handle 123145446559744, query id 267 localhost root 
  4. TABLE LOCK table `test`.`id_ni_rc` trx id 1446 lock mode IX 
  5. RECORD LOCKS space id 27 page no 3 n bits 72 index PRIMARY of table `test`.`id_ni_rc` trx id 1446 lock_mode X locks rec but not gap 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  7.  ... 
  8. Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  9.  ... 

看到 TABLE LOCK 的狀態(tài)是 IX 說明沒有加表鎖。同時看到最終鎖住的只有heap_no = 4 和 6 的兩條記錄。

主鍵 + RR

當 ID 為主鍵時,在 RR 隔離級別下,加鎖情況與一致,都是對主鍵記錄加 Record Lock。

唯一索引 + RR

當 ID 為唯一索引時,在 RR 隔離級別下,加鎖情況與一致,都是對索引記錄和聚簇索引/主鍵 Record Lock。

非唯一索引 + RR

結(jié)論:對索引記錄 Next Key Lock,末尾加 Gap Lock,同時對主鍵加 Record Lock

Repeatable Read 和 Read Committed 隔離級別的主要區(qū)別是 RR 要防止幻讀?;米x指的是執(zhí)行同一個 SQL 兩次得到的結(jié)果不同。考慮下面的場景:

 

  1. SELECT count(*) FROM t WHERE id = 5 FOR UPDATE 
  2. id = 5 
  3. SELECT count(*) FROM t WHERE id = 5 FOR UPDATE 

為了要避免這種情況,在 RR 隔離級別下,在 #1 執(zhí)行時不僅要鎖住現(xiàn)有的 ID=5 的索引,還需要阻止 ID = 5 的記錄插入(即 #2)。而 Gap Lock 就是實現(xiàn)這個目的的一種手段。

考慮到索引是有序的,因此如果索引里有 [3, 5, 5, 7] 這幾個元素,則可以通過鎖住 (3, 5) 、 (5, 7) 這幾個區(qū)間,加上 [5] 這幾個已經(jīng)存在的元素,就可以阻止 ID = 5 的記錄插入。Gap Lock(間隙鎖)的含義是鎖住區(qū)間,而如果加上右邊的閉區(qū)間,如 (3, 5] 就稱為記錄 5 的 Next-Key Lock。

InnoDB 在掃描行時會為掃到的行加上 Next-Key Lock,對于上面的數(shù)據(jù),掃到記錄 5 時,會加上 (3, 5] 鎖,同時,還會對下一個記錄加上 Gap Lock,即 (5, 7) ,造成 (3, 7) 都無法插入的現(xiàn)象,驗證 MySQL 實現(xiàn)如下:

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_si_rr(pk int primary key, id intname varchar(32)); 
  3. CREATE INDEX id_si ON id_si_rr(id); 
  4.  
  5.  
  6. -- 準備數(shù)據(jù) 
  7. INSERT INTO id_si_rr values(1, 1, 'a'); 
  8. INSERT INTO id_si_rr values(2, 3, 'b'); 
  9. INSERT INTO id_si_rr values(3, 5, 'c'); 
  10. INSERT INTO id_si_rr values(4, 7, 'c'); 
  11. INSERT INTO id_si_rr values(5, 5, 'b'); 

執(zhí)行語句:

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_si_rr WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志(省略 PHYSICAL RECORD 的內(nèi)容):

 

  1. ---TRANSACTION 929891, ACTIVE 6 sec 
  2. 4 lock struct(s), heap size 1136, 5 row lock(s), undo log entries 2 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9442 localhost root 
  4. TABLE LOCK table `test`.`id_si_rr` trx id 929891 lock mode IX 
  5. RECORD LOCKS space id 1820 page no 4 n bits 72 index id_si of table `test`.`id_si_rr` trx id 929891 lock_mode X 
  6. Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
  7.  ... 
  8. Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
  9.  ... 
  10.  
  11. RECORD LOCKS space id 1820 page no 3 n bits 72 index PRIMARY of table `test`.`id_si_rr` trx id 929891 lock_mode X locks rec but not gap 
  12. Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  13.  ... 
  14. Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  15.  ... 
  16.  
  17. RECORD LOCKS space id 1820 page no 4 n bits 72 index id_si of table `test`.`id_si_rr` trx id 929891 lock_mode X locks gap before rec 
  18. Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 
  19.  ... 

首先我們看到:

 

  1. id_si 
  2. id_si 

為什么唯一索引 + RR 就不需要 Gap Lock 呢?是因為我們的核心目的是不讓其它事務(wù)插入 ID = 5 的記錄,如果 ID 是唯一索引,鎖住記錄本身就能夠滿足要求了,不再需要 Gap Lock。

無索引 + RR

結(jié)論:對所有行都加記錄鎖,且索引前后都要加 Gap Lock

首先建表準備數(shù)據(jù):

 

  1. -- 建表 
  2. CREATE TABLE id_ni_rr(pk int primary key, id intname varchar(32)); 
  3.  
  4. -- 準備數(shù)據(jù) 
  5. INSERT INTO id_ni_rr values(1, 1, 'a'); 
  6. INSERT INTO id_ni_rr values(2, 3, 'b'); 
  7. INSERT INTO id_ni_rr values(3, 5, 'c'); 
  8. INSERT INTO id_ni_rr values(4, 7, 'c'); 
  9. INSERT INTO id_ni_rr values(5, 5, 'b'); 

執(zhí)行語句:

 

  1. -- 設(shè)置為 RC 隔離級別 
  2. SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
  3. BEGIN-- 開啟事務(wù) 
  4. DELETE FROM id_ni_rr WHERE id = 5; 
  5. -- 先不結(jié)束事務(wù),驗證 Monitor Output 再用 ROLLBACK; 回滾 

Monitor 輸出日志(省略了部分信息):

 

  1. ---TRANSACTION 929980, ACTIVE 5 sec 
  2. 2 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 2 
  3. MySQL thread id 1309, OS thread handle 123145430310912, query id 9529 localhost root 
  4. TABLE LOCK table `test`.`id_ni_rr` trx id 929980 lock mode IX 
  5. RECORD LOCKS space id 1822 page no 3 n bits 72 index PRIMARY of table `test`.`id_ni_rr` trx id 929980 lock_mode X 
  6. Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 
  7.  0: len 8; hex 73757072656d756d; asc supremum;; 
  8.  
  9. Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 
  10.  ... 
  11. Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 
  12.  ... 
  13. Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  14.  ... 
  15. Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 
  16.  ... 
  17. Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  18.  ... 

首先看到 TABLE LOCK 的狀態(tài)是 IX 說明沒有加表鎖。同時看到鎖住了 heap no 2~6的記錄,對應(yīng)數(shù)據(jù)庫中的 5 條記錄。另外這里的鎖是 Next Key Lock,加上 heap no 為 1 的 “supremum” 記錄的 gap lock,鎖住了所有已經(jīng)存在和不存在的行。因此如果執(zhí)行 SELECT * FROM id_ni_rc WHERE id = 0 FOR UPDATE 也會阻塞,盡管 0 記錄不在數(shù)據(jù)庫中。

死鎖驗證

死鎖與獲取鎖的順序有關(guān),一條語句(如 INSERT、DELETE)中對不同行、不同索引的加鎖存在先后,因此不同事務(wù)內(nèi)的語句執(zhí)行時,有可能產(chǎn)生死鎖。常見死鎖原因(摘自 MySQL InnoDB鎖和死鎖 ):

  • 同一索引上,兩個session相反的順序加鎖多行記錄
  • UPDATE/DELETE 通過不同的二級索引更新多條記錄,可能造成在 Primary key 上不同的加鎖順序
  • Primary key 和 Secondary index,通過 primary key 找到記錄,更新 Secondary index 字段與通過 Secondary index 更新記錄

樣例情形:

首先建表準備數(shù)據(jù):

 

  1. CREATE TABLE deadlock(id int primary keyname varchar(32), reg int); 
  2. CREATE INDEX deadlock_name ON deadlock(name); 
  3. CREATE INDEX deadlock_reg ON deadlock(reg); 
  4.  
  5. -- 準備數(shù)據(jù) 
  6. INSERT INTO deadlock values(1, 'x', 5); 
  7. INSERT INTO deadlock values(2, 'b', 4); 
  8. INSERT INTO deadlock values(3, 'x', 3); 
  9. INSERT INTO deadlock values(4, 'd', 2); 
  10. INSERT INTO deadlock values(5, 'e', 1); 

兩個事務(wù)分別“同時”執(zhí)行:

 

  1. -- Transaction A                       | -- Transaction B 
  2. DELETE FROM deadlock WHERE name = 'x'; | DELETE FROM deadlock WHERE reg >= 2; 

其中一個事務(wù)可能會檢測到死鎖而出錯。Monitor 日志里找到 “LATEST DETECTED DEADLOCK” 可以看到記錄的死鎖原因(這個示例復(fù)現(xiàn)出的問題與上圖不直接一致):

 

  1. ------------------------ 
  2. LATEST DETECTED DEADLOCK 
  3. ------------------------ 
  4. 2020-12-13 15:59:40 0x700007a56000 
  5. *** (1) TRANSACTION
  6. TRANSACTION 930064, ACTIVE 0 sec starting index read 
  7. mysql tables in use 1, locked 1 
  8. LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s) 
  9. MySQL thread id 1309, OS thread handle 123145430310912, query id 9616 localhost root updating 
  10. DELETE FROM deadlock WHERE name = 'x' 
  11. *** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
  12. RECORD LOCKS space id 1825 page no 3 n bits 72 index PRIMARY of table `test`.`deadlock` trx id 930064 lock_mode X locks rec but not gap waiting 
  13. Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  14.  ... 
  15.  
  16. *** (2) TRANSACTION
  17. TRANSACTION 930063, ACTIVE 0 sec updating or deleting 
  18. mysql tables in use 1, locked 1 
  19. 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1 
  20. MySQL thread id 1308, OS thread handle 123145430589440, query id 9615 localhost root updating 
  21. DELETE FROM deadlock WHERE reg >= 2 
  22. *** (2) HOLDS THE LOCK(S): 
  23. RECORD LOCKS space id 1825 page no 3 n bits 72 index PRIMARY of table `test`.`deadlock` trx id 930063 lock_mode X 
  24. Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 32 
  25.  ... 
  26.  
  27. *** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
  28. RECORD LOCKS space id 1825 page no 4 n bits 72 index deadlock_name of table `test`.`deadlock` trx id 930063 lock_mode X locks rec but not gap waiting 
  29. Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 
  30.  ... 
  31.  
  32. *** WE ROLL BACK TRANSACTION (1) 

我們看到:

  • 第一個事務(wù)在等待 PRIMARY 索引上 heap_no = 2 的記錄的 Record Lock
  • 第二個事務(wù)已經(jīng)取得 PRIMARY 索引上 heap_no = 2 的 Next Key Lock
  • 同時第二個事務(wù)在等待 deadlock_name 索引上 heap_no = 2 的 Record Lock
  • MySQL 選擇回滾第一個事務(wù)

更新操作如 UPDATE/DELETE 加鎖的順序為: 查詢索引 > 主鍵索引 > 其它二級索引 。如上例中,第二個事務(wù)已經(jīng)鎖住了主鍵索引,準備鎖住另一個二級索引 deadlock_name ,而第一個已經(jīng)鎖住了 deadlock_name ,準備鎖主鍵索引,造成死鎖。

責(zé)任編輯:未麗燕 來源: lotabout.me
相關(guān)推薦

2010-11-15 13:47:13

oracle記錄加鎖

2009-07-16 16:51:56

WebWork驗證機制

2017-05-15 18:00:43

MySQ加鎖處理

2020-11-08 14:32:01

JavaScript變量內(nèi)存管理

2009-03-20 14:38:14

CAM介紹CAMXML結(jié)構(gòu)驗證

2010-10-29 10:56:46

ORACLE用戶驗證

2017-08-30 18:15:54

MySql

2020-07-16 21:20:08

數(shù)據(jù)庫MySQL死鎖

2022-12-29 09:49:06

輕量級架構(gòu)決策

2010-01-04 10:34:01

Silverlight

2021-11-11 13:05:25

MySQLINSERT

2021-06-08 09:41:26

MySQL加鎖范圍

2013-05-03 09:44:52

2012-02-20 09:55:41

ibmdw

2021-06-05 18:02:20

MySQL加鎖范圍

2022-11-09 10:46:18

AQS加鎖機制

2021-09-06 18:55:57

MySQLCheckpoint機制

2021-06-06 13:03:53

MySQL普通索引

2023-03-27 17:58:34

MySQL加鎖間隙鎖

2017-06-02 08:48:29

互斥鎖JavaCAS
點贊
收藏

51CTO技術(shù)棧公眾號