程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQLInnoDB鎖機制(二)

MySQLInnoDB鎖機制(二)

編輯:MySQL綜合教程

MySQLInnoDB鎖機制(二)


MySQL InnoDB支持三種行鎖定方式:

行鎖(Record Lock):鎖直接加在索引記錄上面。間隙鎖(Gap Lock):鎖加在不存在的空閒空間,可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最後一個索引之後的空間。Next-Key Lock:行鎖與間隙鎖組合起來用就叫做Next-Key Lock。

默認情況下,InnoDB工作在可重復讀隔離級別下,並且以Next-Key Lock的方式對數據行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖與間隙鎖的組合,這樣,當InnoDB掃描索引記錄的時候,會首先對選中的索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。如果一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的。

 

我們來看看例子,首先建一張表。

CREATE TABLE tb1 (
  id int(11) NOT NULL,
  id2 int(11) NOT NULL,
  PRIMARY KEY (id),
  KEY idx (id2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

創建一些記錄。

insert into tb1 values(1, 3), (2, 6), (3, 9);

 

tb1表現在有3條記錄,其中普通索引字段id2的值3、6、9把間隙分成了四份:(-,3)、(3、6)、(6、9)、(9、+)。現在我們看看基於id2 = 6加鎖的情況,會話S1中對id2 = 6的記錄加S鎖。

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1 where id2 = 6 lock in share mode;
+----+-----+
| id | id2 |
+----+-----+
|  2 |   6 |
+----+-----+
1 row in set (0.00 sec)

mysql>

 

會話S2中嘗試插入id2 = 5或id2 = 7的記錄。

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1 values(4, 5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tb1 values(4, 7);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

 

從結果可知,會話2發生了鎖等待超時,因為會話S1中的事務鎖住了這些空隙(3、6)與(6、9)。如果插入的記錄是id2 = 1或id2 = 10,那就不會有問題,因為這些間隙沒有被任何事務鎖住,如:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1 values(4, 5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tb1 values(4, 7);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into tb1 values(4, 2);
Query OK, 1 row affected (0.00 sec)

mysql> insert into tb1 values(5, 10);
Query OK, 1 row affected (0.00 sec)

mysql>

 

間隙鎖在InnoDB的唯一作用就是防止其它事務的插入操作,以此來達到防止幻讀的發生,所以間隙鎖不分什麼共享鎖與排它鎖。另外,在上面的例子中,我們選擇的是一個普通(非唯一)索引字段來測試的,這不是隨便選的,因為如果InnoDB掃描的是一個主鍵、或是一個唯一索引的話,那InnoDB只會采用行鎖方式來加鎖,而不會使用Next-Key Lock的方式,也就是說不會對索引之間的間隙加鎖,仔細想想的話,這個並不難理解,大家也可以自己測試一下。

 

要禁止間隙鎖的話,可以把隔離級別降為讀已提交,或者開啟參數innodb_locks_unsafe_for_binlog。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved