1. 程式人生 > >MySQL GAP鎖初步認識

MySQL GAP鎖初步認識

鎖,在現實生活中是為我們想要隱藏於外界所使用的一種工具。在計算機中,是協調多個程序或縣城併發訪問某一資源的一種機制。在資料庫當中,除了傳統的計算資源(CPU、RAM、I/O等等)的爭用之外,資料也是一種供許多使用者共享訪問的資源。如何保證資料併發訪問的一致性、有效性,是所有資料庫必須解決的一個問題,鎖的衝突也是影響資料庫併發訪問效能的一個重要因素。從這一角度來說,鎖對於資料庫而言就顯得尤為重要。

MySQL中根據鎖粒度分三種鎖機制:行鎖(鎖定粒度小,發生鎖衝突的概率低,併發度高),表鎖(鎖定力度大,發生鎖衝突概率高,併發度最低),頁鎖(鎖定粒度介於表鎖和行鎖之間,併發度一般)。

而常用的InnoDB

儲存引擎實現了以下兩種型別的行鎖。

  共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同資料集的排他鎖。

  排他鎖(X):允許獲得排他鎖的事務更新資料,阻止其他事務取得相同資料集的共享讀鎖和排他寫鎖。

  另外,為了允許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。

  意向共享鎖(IS):事務打算給資料行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。

意向排他鎖(IX):事務打算給資料行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。

今天我們主要了解下X鎖中的gap鎖:

MySQL GAP

鎖存在於MySQL隔離級別為REPEATABLE-READ或更高級別情況下,為了防止幻讀,於是有gap鎖和next-key鎖存在,除了對唯一索引的唯一搜索外都會獲取gap鎖或next-key鎖。即鎖住其掃描的範圍。

下面我們分別做相應的測試:

測試一:非唯一索引

隔離級別:REPEATABLE-READ

表結構:id為非唯一索引

表內容:

mysql>select * from test2;

+------+----------+

| id   | name    |

+------+----------+

|   10 | xbb     |

|   20 | Michael  |

|   30 | bingo   |

+------+----------+

3 rows in set(0.00 sec)

session1:update一條記錄(未提交)

mysql> setautocommit =0;

Query OK, 0rows affected (0.00 sec)

mysql>update test2 set name='icey' where id=20;

Query OK, 1 rowaffected (0.00 sec)

Rows matched:1  Changed: 1  Warnings: 0

session2:insert記錄

mysql> setautocommit =0;

Query OK, 0rows affected (0.00 sec)

mysql>insert into test2 values(10,'aa');

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

mysql>insert into test2 values(16,'aa');

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

mysql> insertinto test2 values(22,'aa');

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

mysql>insert into test2 values(30,'aa');

Query OK, 1 rowaffected (0.00 sec)

mysql>UPDATE  test2 set name='icey' whereid=10;

Query OK, 1 rowaffected (0.00 sec)

Rows matched:1  Changed: 1  Warnings: 0

 

mysql>UPDATE  test2 set name='icey' whereid=20;

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

mysql>UPDATE  test2 set name='icey' whereid=30;

Query OK, 2rows affected (0.00 sec)

Rows matched:2  Changed: 2  Warnings: 0

 

mysql>delete from test2 where id =20;

ERROR 1205(HY000): Lock wait timeout exceeded; try restarting transaction

mysql>delete from test2 where id =11;

Query OK, 0rows affected (0.00 sec)

 

檢視鎖內容:

---TRANSACTION50833735, ACTIVE 780 sec inserting

mysql tables inuse 1, locked 1

LOCK WAIT 2lock struct(s), heap size 1184, 1 row lock(s), undo log entries 2

MySQL thread id4230, OS thread handle 0x7f54a3a4d700, query id 17513177 localhost root update

insert intotest2 values(16,'aa')

Trx read viewwill not see trx with id >= 50833736, sees < 50833736

------- TRX HASBEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:

RECORD LOCKSspace id 13379 page no 4 n bits 80 index `idx_id` of table `test`.`test2` trx id50833735 lock_mode Xlocks gap before recinsert intention waiting

---TRANSACTION50835541, ACTIVE 62 sec starting index read

mysql tables inuse 1, locked 1

LOCK WAIT 2lock struct(s), heap size 360, 1 row lock(s)

MySQL thread id4230, OS thread handle 0x7f54a3a4d700, query id 17513933 localhost rootSearching rows for update

update test2set name ='meachel' where id=20

Trx read viewwill not see trx with id >= 50835542, sees < 50835513

------- TRX HASBEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:

RECORD LOCKSspace id 13379 page no 4 n bits 80 index `idx_id` of table `test`.`test2` trxid 50835541 lock_mode Xwaiting

---TRANSACTION50835541, ACTIVE 185 sec starting index read

mysql tables inuse 1, locked 1

LOCK WAIT 2lock struct(s), heap size 360, 1 row lock(s)

MySQL thread id4230, OS thread handle 0x7f54a3a4d700, query id 17514179 localhost rootupdating

delete fromtest2 where id =20

Trx read viewwill not see trx with id >= 50835542, sees < 50835513

------- TRX HASBEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED:

RECORD LOCKSspace id 13379 page no 4 n bits 80 index `idx_id` of table `test`.`test2` trxid 50835541 lock_mode X waiting

由此可知:在隔離級別是RR或者更高的情況下,事務一對某記錄進行update(select * for update)時,未提交,

當事務二insert表記錄的時候將會gap鎖,鎖的範圍是[上條記錄,下一條記錄)。

當事務二update,delete表記錄的時候將只有X鎖,即只對事務更新的那條記錄加X鎖。

當表中無索引,無主鍵。當事務一進行更新記錄,將鎖全表,事務二無法進行insert,update,delete操作。

當表中有主鍵或者唯一索引。Update/delete一條不存在記錄,則也會產生gap鎖。