1. 程式人生 > >Mysql中那些鎖機制之InnoDB

Mysql中那些鎖機制之InnoDB

插入記錄 都在 讀一行 利用 分數 .net new 第二版 delet

我們知道mysql在曾經。存儲引擎默認是MyISAM。可是隨著對事務和並發的要求越來越高,便引入了InnoDB引擎。它具有支持事務安全等一系列特性。

InnoDB鎖模式

InnoDB實現了兩種類型的行鎖。

共享鎖(S同意一個事務去讀一行,阻止其它事務獲得同樣的數據集的排他鎖。

排他鎖(X同意獲得排他鎖的事務更新數據,可是組織其它事務獲得同樣數據集的共享鎖和排他鎖。

能夠這麽理解:

共享鎖就是我讀的時候,你能夠讀,可是不能寫。排他鎖就是我寫的時候。你不能讀也不能寫。事實上就是MyISAM的讀鎖和寫鎖,可是針對的對象不同了而已。

除此之外InnoDB還有兩個表鎖:

意向共享鎖(IS

表示事務準備給數據行增加共享鎖。也就是說一個數據行加共享鎖前必須先取得該表的IS

意向排他鎖(IX類似上面,表示事務準備給數據行增加排他鎖,說明事務在一個數據行加排他鎖前必須先取得該表的IX鎖。


InnoDB行鎖模式兼容列表:

技術分享

技術分享

註意:

當一個事務請求的鎖模式與當前的鎖兼容。InnoDB就將請求的鎖授予該事務;反之假設請求不兼容,則該事務就等待鎖釋放。

意向鎖是InnoDB自己主動加的。不須要用戶幹預。

對於insertupdatedeleteInnoDB會自己主動給涉及的數據加排他鎖(X);對於一般的Select語句,InnoDB不會加不論什麽鎖,事務能夠通過下面語句給顯示加共享鎖或排他鎖。

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

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


增加共享鎖的樣例:

技術分享

技術分享


利用select ....for update增加排他鎖


技術分享技術分享



鎖的實現方式:

InnoDB行鎖是通過給索引項加鎖實現的。假設沒有索引,InnoDB會通過隱藏的聚簇索引來對記錄加鎖。

也就是說:假設不通過索引條件檢索數據。那麽InnoDB將對表中全部數據加鎖。實際效果跟表鎖一樣。

行鎖分為三種情形:

Record lock

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

Gap lock對索引項之間的‘間隙’、對第一條記錄前的間隙或最後一條記錄後的間隙加鎖,即鎖定一個範圍的記錄,不包括記錄本身

Next-key Lock:鎖定一個範圍的記錄並包括記錄本身(上面兩者的結合)。

註意:InnoDB默認級別是repeatable-read級別,所以以下說的都是在RR級別中的。


之前一直搞不懂Gap LockNext-key Lock的差別,直到在網上看到一句話豁然開朗,希望對各位有幫助。

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]和(69] 都增加了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、當事務須要更新大部分數據時。表又比較大。假設使用默認的行鎖,不僅效率低。並且還easy造成其它事務長時間等待和鎖沖突。

2、事務比較復雜。非常可能引起死鎖導致回滾。

死鎖:

我們說過MyISAM中是不會產生死鎖的,由於MyISAM總是一次性獲得所需的所有鎖,要麽所有滿足。要麽所有等待。

而在InnoDB中。鎖是逐步獲得的。就造成了死鎖的可能。

在上面的樣例中我們可以看到。當兩個事務都須要獲得對方持有的鎖才可以繼續完畢事務,導致兩方都在等待。產生死鎖。

發生死鎖後,InnoDB一般都能夠檢測到,並使一個事務釋放鎖回退。還有一個獲取鎖完畢事務。

避免死鎖:

有多種方法能夠避免死鎖,這裏僅僅介紹常見的三種:

1、假設不同程序會並發存取多個表,盡量約定以同樣的順序訪問表。能夠大大減少死鎖機會。

2、在同一個事務中。盡可能做到一次鎖定所須要的全部資源,降低死鎖產生概率;

3、對於很easy產生死鎖的業務部分,能夠嘗試使用升級鎖定顆粒度,通過表級鎖定來降低死鎖產生的概率;



參考:

Innodb中的事務隔離級別和鎖的關系

MySQL InnoDB鎖機制(二)

Innodb鎖機制:Next-Key Lock 淺談

深入淺出Mysql數據庫開發、優化與管理維護.第二版






Mysql中那些鎖機制之InnoDB