2012-02-19 88 views
7

我正在閱讀有關innodb交易的手冊,但仍然有很多不清楚的東西給我。舉例來說,我不太明白以下行爲:inno db隔離級別和鎖定

-- client 1        -- client 2 
mysql> create table simple (col int) 
     engine=innodb; 

mysql> insert into simple values(1); 
Query OK, 1 row affected (0.00 sec) 

mysql> insert into simple values(2); 
Query OK, 1 row affected (0.00 sec) 

mysql> select @@tx_isolation;                
+-----------------+                   
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ |                   
+-----------------+ 

mysql> begin;          
Query OK, 0 rows affected (0.01 sec)    
             mysql> begin; 
             Query OK, 0 rows affected (0.00 sec) 

mysql> update simple set col=10 where col=1; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

             mysql> update simple set col=42 where col=2; 
             -- blocks 

現在,最後更新命令(在客戶端2)等待。我期望命令執行,因爲我會假設只有行1被鎖定。即使客戶端2中的第二個命令是insert,行爲也是一樣的。任何人都可以描述這個例子背後的鎖定背景(在哪裏和爲什麼鎖)?

+1

閱讀關於**'REPEATABLE READ' **:[Transaction levels](http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html):'For locking reads( SELECT FOR FOR UPDATE或LOCK IN SHARE MODE),UPDATE和DELETE語句,鎖定**取決於語句是使用具有唯一搜索條件**的唯一索引,還是範圍類型搜索條件。 ...' – 2012-02-19 22:49:51

回答

9

InnoDB按如下方式設置特定類型的鎖。

  • SELECT ... FROM是一個持續讀,讀取數據庫的快照,除非事務隔離級別設置爲序列的設置沒有鎖。對於SERIALIZABLE級別,搜索會在遇到的索引記錄上設置共享的下一個鍵鎖。

  • SELECT ... FROM ...鎖定共享模式在搜索遇到的所有索引記錄上設置共享的下一個鍵鎖定。

  • 對於搜索遇到的索引記錄,SELECT ... FROM ... FOR UPDATE阻止其他會話執行SELECT ... FROM ... LOCK IN SHARE MODE或讀取某些事務隔離級別。一致的讀取操作將忽略讀取視圖中存在的記錄上設置的任何鎖定。

  • UPDATE ... WHERE ...在搜索遇到的每個記錄上設置獨佔的下一個鍵鎖定。

  • DELETE FROM ... WHERE ...在搜索遇到的每條記錄上設置獨佔的下一個鍵鎖定。

  • INSERT在插入的行上設置排它鎖。該鎖是一個索引記錄鎖,而不是下一個鍵鎖(即沒有間隙鎖),並且不會阻止其他會話插入到插入行之前的間隙中。

InnoDB的有幾種類型的記錄級鎖:

  • 記錄鎖:這是一個索引記錄鎖。

  • 間隙鎖定:這是鎖定索引記錄之間的間隙,或鎖定第一個或最後一個索引記錄之後的間隙。

  • 下一個鍵鎖定:這是索引記錄上的記錄鎖定和索引記錄之前的間隙上的間隙鎖定的組合。

查看更多:

Avoiding the Phantom Problem Using Next-Key Locking

Avoiding deadlock

+0

良好的概述,但我想知道如何索引適合你寫的東西。爲什麼索引的存在會改變我的示例中的行爲? – clime 2012-02-24 11:40:09

+2

下一個鍵鎖定結合了索引行鎖定和間隙鎖定。 InnoDB以這樣的方式執行行級鎖定,即當它搜索或掃描表索引時,它會在遇到的索引記錄上設置共享鎖或排它鎖。另外,索引記錄上的下一個鍵鎖也會影響該索引記錄之前的「間隙」。也就是說,下一個鍵鎖定是索引記錄鎖定,並在索引記錄之前的間隔上加上間隙鎖定。 – 2012-02-24 12:30:24

0

ypercube有它的權利。具體而言,如果沒有在條件中使用的唯一索引,它將鎖定多於受影響的單個行。

要查看您所期望的行爲,你的表創建改成這樣:

create table simple (col int unique) ENGINE=InnoDB; 

col領域唯一索引將允許它僅鎖定受影響的行。

+0

正如我發現的那樣,需要有一個索引,但它不需要是唯一的。 – clime 2012-02-24 11:29:02

+0

啊,當我讀到它'使用唯一的索引和獨特的搜索條件'時,我將它作爲'唯一'索引,但它們必須具有唯一性,就像單一的特定索引一樣。 – kbenson 2012-02-24 19:34:48

+0

ypercube寫的不是(完全)相關的。如果有唯一的索引和唯一的搜索條件,則使用記錄鎖而不是下一個鍵鎖。在我的示例中,使用記錄鎖定或下一個鍵鎖定並不重要,因爲只有第一次更新可能鎖定的間隔是1之前,第二次更新引用了2。重要的是存在(y )索引,因爲update不會僅鎖定目標記錄,而是鎖定在搜索目標記錄_期間遇到的所有記錄。沒有索引=>全面掃描=>所有記錄被鎖定。 – clime 2012-02-24 19:58:03

0

「對於索引記錄搜索遇到,SELECT ... FROM ... FOR UPDATE阻止執行SELECT其他會話.. 。FROM ...鎖定在共享模式下或從某些事務隔離級別讀取。一致的讀取將忽略在讀取視圖中存在的記錄上設置的任何鎖定「

這些特定的鎖可以通過select來更新,以便其他會話無法讀取鎖定的記錄?

+0

對不起,這不是一個答案。考慮發佈一個單獨的問題。 – Beryllium 2014-06-16 06:52:38

+0

stalkoverflow人們不允許我發佈它作爲一個新問題 – ravi 2014-06-16 12:52:57

+0

在mysql中沒有這樣的鎖定,請參閱[本答案](http://stackoverflow.com/a/21792907/3576887)瞭解變通辦法 – elipoultorak 2015-12-29 08:22:15