MySQL GAP鎖初步認識
鎖,在現實生活中是為我們想要隱藏於外界所使用的一種工具。在計算機中,是協調多個程序或縣城併發訪問某一資源的一種機制。在資料庫當中,除了傳統的計算資源(CPU、RAM、I/O等等)的爭用之外,資料也是一種供許多使用者共享訪問的資源。如何保證資料併發訪問的一致性、有效性,是所有資料庫必須解決的一個問題,鎖的衝突也是影響資料庫併發訪問效能的一個重要因素。從這一角度來說,鎖對於資料庫而言就顯得尤為重要。
MySQL中根據鎖粒度分三種鎖機制:行鎖(鎖定粒度小,發生鎖衝突的概率低,併發度高),表鎖(鎖定力度大,發生鎖衝突概率高,併發度最低),頁鎖(鎖定粒度介於表鎖和行鎖之間,併發度一般)。
而常用的InnoDB
共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同資料集的排他鎖。
排他鎖(X):允許獲得排他鎖的事務更新資料,阻止其他事務取得相同資料集的共享讀鎖和排他寫鎖。
另外,為了允許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。
意向共享鎖(IS):事務打算給資料行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。
意向排他鎖(IX):事務打算給資料行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。
今天我們主要了解下X鎖中的gap鎖:
MySQL GAP
下面我們分別做相應的測試:
測試一:非唯一索引
隔離級別: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鎖。