my40_MySQL锁概述之意向锁
本文在鎖概述的基礎(chǔ)上,通常實(shí)驗(yàn)舉例,詳細(xì)地介紹了意向鎖的原理。
鎖范圍
全局鎖(global lock)
表鎖(table lock)
行鎖 (row lock)
ROW LOCK的粒度
LOCK_REC_NOG_GAP, record lock with out gap lock
LOCK_GAP, gap lock
LOCK_ORDINARY , next key lock = record lock + gap lock
鎖等待與死鎖
鎖等待 事務(wù)提交或等待超時(shí);死鎖,是一個(gè)死循環(huán)。死鎖中必有鎖等待。
表鎖
5.5以后在server層實(shí)現(xiàn)表鎖
innodb中有IS/IX表級(jí)鎖,以及自增鎖(auto-inc)
讀鎖
加讀鎖后,只能對(duì)表讀,不能對(duì)表寫(xiě);允許多個(gè)會(huì)話同時(shí)讀;其他會(huì)話可以加共享讀鎖
lock tabletable_name read
寫(xiě)鎖
lock table table_name write
持有鎖的會(huì)話可寫(xiě)可讀
其他會(huì)話訪問(wèn)表或請(qǐng)求加鎖都會(huì)被阻塞,直到鎖釋放
釋放鎖
unlock tables;
lock table 鎖不能相互嵌套,一個(gè)事務(wù)開(kāi)始就意味著另外一個(gè)事務(wù)結(jié)束
顯式開(kāi)啟一個(gè)事務(wù),因?yàn)槭聞?wù)中不能支持表鎖,所以事務(wù)開(kāi)始則表鎖斷開(kāi)
Kill或連接斷開(kāi)
innodb鎖
默認(rèn)為行鎖
在索引上加鎖來(lái)實(shí)現(xiàn)行鎖
如果沒(méi)有索引,那么升級(jí)為全表記錄鎖,最終效果等同于表鎖;但表鎖只需要在根節(jié)點(diǎn)上加鎖,而不是對(duì)所有記錄加鎖,所以代價(jià)要小一些
鎖類(lèi)型
共享鎖
排他鎖/獨(dú)占鎖
意向鎖,innodb特有,加在表級(jí)別上的鎖
共享鎖與獨(dú)占鎖均用于事務(wù)當(dāng)中,隨事務(wù)的結(jié)束而解除。
共享鎖(share lock)
又稱(chēng)讀鎖,讀取操作創(chuàng)建的鎖。
一旦上鎖,任何事務(wù)(包括當(dāng)前事務(wù))無(wú)法對(duì)其修改,其他事務(wù)可以并發(fā)讀取數(shù)據(jù),也可在對(duì)此數(shù)據(jù)再加共享鎖
語(yǔ)法:SELECT ... LOCK IN SHARE MODE;
排他鎖(exclusive lock)
又稱(chēng)寫(xiě)鎖,如果事務(wù)對(duì)數(shù)據(jù)A加上排他鎖后,則其他事務(wù)不可并發(fā)讀取數(shù)據(jù),也不能再對(duì)A加任何類(lèi)型的鎖。獲得排他鎖的事務(wù)既能讀數(shù)據(jù),又能修改數(shù)據(jù)。
語(yǔ)法:SELECT ... FOR UPDATE
這里的“其他事務(wù)不可并發(fā)讀取數(shù)據(jù)”,指的是不可以加共享鎖,即不可以以lock in share mode的方式讀取數(shù)據(jù),比如
會(huì)話一
mysql> select * from test for update; +----+------+------+ | id | v1 | v2 | +----+------+------+ | 1 | 1 | 0 | | 2 | 3 | 1 | | 3 | 4 | 2 | | 5 | 5 | 3 | | 7 | 7 | 4 | | 10 | 9 | 5 | +----+------+------+ 6 rows in set (0.00 sec)
會(huì)話二:
mysql> select * from test lock in share mode; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
直接查詢(xún)完全可以
mysql> select * from test; +----+------+------+ | id | v1 | v2 | +----+------+------+ | 1 | 1 | 0 | | 2 | 3 | 1 | | 3 | 4 | 2 | | 5 | 5 | 3 | | 7 | 7 | 4 | | 10 | 9 | 5 | +----+------+------+ 6 rows in set (0.00 sec)
這是因?yàn)橹苯硬樵?xún)走的是一致性快照讀,讀的是MVCC版本控制下的快照,不加鎖;換句話說(shuō),排他鎖排斥的“讀”,是指S鎖下的讀,或者說(shuō)是當(dāng)前讀
意向鎖
InnoDB的表級(jí)鎖,其設(shè)計(jì)目的主要是為了在一個(gè)事務(wù)中揭示下一步將要被請(qǐng)求的鎖的類(lèi)型。
InnoDB中的兩個(gè)表鎖:
意向共享鎖(IS):表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入共享鎖,也就是說(shuō)一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖
意向排他鎖(IX):類(lèi)似上面,表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入排他鎖,說(shuō)明事務(wù)在一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖。
意向鎖是InnoDB自動(dòng)加的,不需要用戶(hù)干預(yù)。
意向鎖是表級(jí)鎖
事務(wù)要獲取表A某些行的S鎖必須要獲取表A的IS鎖
事務(wù)要獲取表A某些行的X鎖必須要獲取表A的IX鎖
上表描述幾種鎖之間的的關(guān)系,其中AI是自增鎖,表主健自增用到。
會(huì)話一鎖定了全表
會(huì)話二,結(jié)果集為空時(shí)不加鎖
意向鎖的目的在于提高innodb性能,會(huì)話一鎖定的是全表,那么會(huì)話二一看全表已被鎖定,則不再去看每行是否鎖定
會(huì)話二先判斷表上有沒(méi)有表鎖,如果沒(méi)有表級(jí)鎖,則開(kāi)始判斷有沒(méi)有行級(jí)鎖
會(huì)話一:不鎖定全表的S鎖
會(huì)話二:立即執(zhí)行,不被鎖;v1上有索引
v1字段上有索引,v2字段上沒(méi)有索引;有索引時(shí),優(yōu)先按有索引的規(guī)則來(lái),當(dāng)字段上沒(méi)有索引時(shí),S鎖,X鎖走意向鎖的邏輯;
會(huì)話一
mysql> begin;select * from test where v1 >4 lock in share mode; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 5 | 5 | 3 | | 7 | 7 | 4 | | 10 | 9 | 5 | +----+------+------+ 3 rows in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> begin;select * from test where v2 >4 lock in share mode; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 10 | 9 | 5 | +----+------+------+ 1 row in set (0.00 sec)
會(huì)話二:
mysql> begin;select * from test where v1 < 2 for update; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 1 | 1 | 0 | +----+------+------+ 1 row in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> mysql> mysql> begin;select * from test where v2 < 2 for update; Query OK, 0 rows affected (0.00 sec) ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql>
如果不是S鎖,而是快照讀的話,不會(huì)走意向鎖的邏輯,因?yàn)榭煺兆x不加鎖(不管是RC還是RR隔離級(jí)別);
會(huì)話一
mysql> begin;select * from test where v2 >4; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 10 | 9 | 5 | +----+------+------+ 1 row in set (0.00 sec)
會(huì)話二:立即執(zhí)行,沒(méi)有鎖等待
mysql> begin;select * from test where v2 < 2 for update; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 1 | 1 | 0 | | 2 | 3 | 1 | +----+------+------+ 2 rows in set (0.00 sec)
對(duì)于無(wú)索引的情況,更新任何一條記錄,都會(huì)對(duì)該表加鎖,這時(shí)意向鎖將非常有用;但這個(gè)場(chǎng)景有個(gè)例外-->“半一致性讀”
半一致性讀的條件:
5.7及以下版本時(shí),需要innodb_locks_unsafe_for_binlog 開(kāi)啟或事務(wù)隔離級(jí)別為RC,語(yǔ)言類(lèi)型為update
8.0版本,語(yǔ)言類(lèi)型為update,事務(wù)隔離級(jí)別為RC;innodb_locks_unsafe_for_binlog 參數(shù)被廢棄。
8.0中半一致性讀測(cè)試
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
會(huì)話一
mysql> begin;select * from test where v2 >4 for update; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 10 | 9 | 5 | +----+------+------+ 1 row in set (8.77 sec)
會(huì)話二:顯式開(kāi)始一個(gè)事務(wù)被阻塞,直接使用update語(yǔ)句不被阻塞;注意v2字段上無(wú)索引
mysql> begin;select * from test where v2 < 2 for update; Query OK, 0 rows affected (0.00 sec) ^C^C -- query aborted ERROR 1317 (70100): Query execution was interrupted mysql> select * from test; +----+------+------+ | id | v1 | v2 | +----+------+------+ | 1 | 1 | 0 | | 2 | 3 | 1 | | 3 | 4 | 2 | | 5 | 5 | 3 | | 7 | 7 | 4 | | 10 | 9 | 5 | +----+------+------+ 6 rows in set (0.00 sec) mysql> update test set v2 = 1 where v2 < 2; Query OK, 1 row affected (0.00 sec) Rows matched: 2 Changed: 1 Warnings: 0 mysql> exit
8.0的RR隔離級(jí)別
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
會(huì)話一:X鎖測(cè)試
mysql> begin;select * from test where v2 >4 for update; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 10 | 9 | 5 | +----+------+------+ 1 row in set (0.00 sec)
會(huì)話二:
mysql> update test set v2 = 1 where v2 < 2; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
8.0中半一致讀的條件:RC及以下隔離級(jí)別,update語(yǔ)句
對(duì)于RR隔離級(jí)別,無(wú)索引的情況下,S鎖,X鎖,走意向鎖的邏輯
會(huì)話一:S鎖測(cè)試
mysql> begin;select * from test where v2 >4 lock in share mode; Query OK, 0 rows affected (0.00 sec) +----+------+------+ | id | v1 | v2 | +----+------+------+ | 10 | 9 | 5 | +----+------+------+ 1 row in set (0.00 sec)
會(huì)話二:
mysql> update test set v2 = 1 where v2 < 2; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
所以意向鎖的關(guān)鍵在于是否是S鎖與X鎖;如果是RC隔離級(jí)別,需要注意一下“半一致性讀”
S鎖會(huì)先有全表上加IS,X鎖會(huì)先在全表上加IX;IS與IX互斥,IX與IX及IS互斥;
對(duì)于經(jīng)常使用的RR隔離級(jí)別,對(duì)于無(wú)索引字段,意向鎖減少了后來(lái)鎖判斷行記錄上是否有鎖的時(shí)間
總結(jié)
以上是生活随笔為你收集整理的my40_MySQL锁概述之意向锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: iOS8 【xcode6中添加pch全局
- 下一篇: gradle中gredle -q 参数是