MySql儲存引擎InnoDB的鎖

2021-08-18 18:04:31 字數 4042 閱讀 6671

innodb實現了以下兩種型別的行鎖:

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

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

共享鎖就是我讀的時候,你可以讀,但是不能寫。排他鎖就是我寫的時候,你不能讀也不能寫。

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

意向共享鎖(is):事務打算給資料行加行共享鎖,事物在給乙個資料行加共享鎖前必須先取得該錶的is鎖。

意向排他鎖(ix):事務打算給資料行加行排他鎖,事務在給乙個資料行加排他鎖前必須先取得該錶的ix鎖。

當乙個事務請求的鎖模式與當前的鎖相容,innodb就將請求的鎖授予該事務;反之如果請求不相容,則該事務就等待鎖釋放。

意向鎖是innodb自動加的,不需要使用者干預。

對於insert、update、delete,innodb會自動給涉及的資料加排他鎖(x);對於一般的select語句,innodb不會加任何鎖,事務可以通過以下語句給顯示加共享鎖或排他鎖。

共享鎖:select * from table_name where …..lock in share mode

排他鎖:select * from table_name where …..for update

加入共享鎖的:

加入排他鎖:

在mysql中,行級鎖並不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql語句操作了主鍵索引,mysql就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,mysql會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。

innodb行鎖是通過給索引項加鎖實現的,如果沒有索引,innodb會通過隱藏的聚簇索引來對記錄加鎖。也就是說,如果不通過索引條件檢索資料,那麼innodb將對錶中所有資料加鎖,實際效果跟表鎖一樣。

行鎖分為三種情形:

record lock:對索引項加鎖,即鎖定一條記錄。

gap lock:對索引項之間的『間隙』、對第一條記錄前的間隙或最後一條記錄後的間隙加鎖,即鎖定乙個範圍的記錄,不包含記錄本身

next-key lock:鎖定乙個範圍的記錄幷包含記錄本身(上面兩者的結合)。

注意:innodb預設級別是repeatable-read級別,所以下面說的都是在rr級別中的。

next-key lock是行鎖與間隙鎖的組合,這樣,當innodb掃瞄索引記錄的時候,會首先對選中的索引記錄加上行鎖(record lock),再對索引記錄兩邊的間隙加上間隙鎖(gap lock)。如果乙個間隙被事務t1加了鎖,其它事務是不能在這個間隙插入記錄的。

假設我們有一張表:

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

| id | age|

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

| 1 | 3 |

| 2 | 6 |

| 3 | 9 |

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

表結構如下:

create

table

`test` (

`id`

int(11) not

null auto_increment,

`age`

int(11) default

null,

primary

key (`id`),

key`keyname` (`age`)

) engine=innodb auto_increment=302

default charset=gbk ;

這樣我們age段的索引就分為

(negative infinity, 3],

(3,6],

(6,9],

(9,positive infinity);

我們來看一下幾種情況:

1、當事務a執行以下語句:

mysql> select * from fenye where age=6for update ;

不僅使用行鎖鎖住了相應的資料行,同時也在兩邊的區間,(5,6]和(6,9] 都加入了gap鎖。

這樣事務b就無法在這個兩個區間insert進新資料,但是事務b可以在兩個區間外的區間插入資料。

2、當事務a執行

select * from fenye where age=7 for update ;

那麼就會給(6,9]這個區間加鎖,別的事務無法在此區間插入或更新資料。

3、如果查詢的資料不再範圍內

比如事務a執行 select * from fenye where age=100 for update ;

那麼加鎖區間就是(9,positive infinity)。

行鎖防止別的事務修改或刪除,gap鎖防止別的事務新增,行鎖和gap鎖結合形成的的next-key鎖共同解決了rr級別在寫資料時的幻讀問題。

何時在innodb中使用表鎖?

innodb在絕大部分情況會使用行級鎖,因為事務和行鎖往往是我們選擇innodb的原因,但是有些情況我們也考慮使用表級鎖。

1、當事務需要更新大部分資料時,表又比較大,如果使用預設的行鎖,不僅效率低,而且還容易造成其他事務長時間等待和鎖衝突。

2、事務比較複雜,很可能引起死鎖導致回滾。

關於這部分內容,有一篇不錯的博文,貼上

mysql的innodb儲存引擎行鎖是加在索引上的,所以只當增刪改查操作是通過索引找到指定資料行的時候,才能對相應資料行的索引加鎖,否則只能對整個表加表鎖,表共享讀鎖或表獨佔寫鎖。

當乙個事務不經過索引查詢資料,即順序讀取(全表掃瞄)時,先獲取表的意向共享鎖,然後對錶新增共享讀鎖,阻止其他事務對錶的更新,新增和刪除操作,但不影響查詢操作,共享讀鎖之間是相容的。

當乙個事務不經過索引更新,刪除資料,即全表掃瞄符合條件的資料行時,先獲取表的意向獨佔鎖,然後對錶新增獨佔寫鎖,在執行更新,刪除時阻止其他事務對錶的讀及寫操作。

當乙個事務使用索引去查詢資料,即隨機讀取時,先獲得表的意向共享鎖,然後對符合條件的的索引區間加共享讀鎖(聚集索引肯定會加鎖,若用到了非聚集索引一樣加鎖),共享讀鎖之間是相容的,因此不影響其他事務對被鎖資料行的訪問。當其他事務想要修改,刪除加鎖的資料行時,若未使用索引則在獲取表獨佔寫鎖時會失敗。若使用索引檢索這些資料行,則可能會在非聚集索引處被阻塞(查詢事務和修改事務使用同乙個索引檢索資料行),也可能在聚集索引處被阻塞(通過非聚集索引查詢到聚集索引的鍵,通過此鍵查詢到相應的聚集索引,同時讀到資料航,這是讀和寫,寫和寫之間的事務序列化保證),只能等待查詢事務釋放索引區間的共享讀鎖,然後執行更新,刪除操作。當乙個事務想要將新的資料行插入到被加鎖的資料行中,也需要等待共享讀鎖的釋放。因為innodb實現了間隙鎖機制,即當乙個事務按乙個條件(id < 10,id列含有索引)加鎖資料行時,其他事務不能在鎖釋放前將符合此條件的資料行(id = 5)插入到表中,此機制一定程度防止了幻讀的出現。猜測實現機制:前乙個事務對資料行的索引加了鎖(聚集索引和非聚集索引),其他的事務插入資料時,需要新增聚集/非聚集索引,但是此時符合條件的聚集/非聚集索引區間已經被加鎖,不能實時插入索引,需要等到索引區間的鎖被釋放,這個可能是間隙鎖的實現原理。

當乙個事務通過索引去更新,刪除資料行時,先獲取表的意向排他鎖,然後對符合條件的資料行的索引加鎖(聚集/非聚集),阻止其他事務對被鎖資料行的讀,寫。同理實現間隙鎖。

MySQL儲存引擎 InnoDB

為什麼innodb不將總數存起來?innodb直接count 會遍歷全表 沒有where條件 雖然結果準確,但會導致效能問題。按照效率排序的話,count 字段 innodb一棵b 樹可以存放多少行資料?這個問題的簡單回答是 約2千萬。為什麼是這麼多呢?因為這是可以算出來的,要搞清楚這個問題,我們先...

MySQL的儲存引擎INNODB

1 一般情況下,mysql會預設提供多種儲存引擎,你可以通過下面的檢視 看你的mysql現在已提供什麼儲存引擎 mysql show engines 看你的mysql當前預設的儲存引擎 mysql show variables like storage engine 你要看某個錶用了什麼引擎 在顯示...

mysql的innodb儲存引擎

innodb是支援事務的儲存引擎,支援acid特性的acid 指資料庫事務正確執行的四個基本要素的縮寫 包含 原子性 atomicity 一致性 consistency 隔離性 isolation 永續性 durability 更適合處理大量的小事務,小事務正常都會被提交,很少會被回滾,在資料儲存的...