2016-06-22 78 views
4

docs的MySQL鎖定在重複鍵錯誤

If a duplicate-key error occurs, a shared lock on the duplicate index record is set. This use of a shared lock can result in deadlock should there be multiple sessions trying to insert the same row if another session already has an exclusive lock. This can occur if another session deletes the row.

與在文檔的例子中去,

假設一個InnoDB表T1具有以下結構:

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB; 

現在假設三個會話按順序執行以下操作:

會話1:

START TRANSACTION; 
INSERT INTO t1 VALUES(1); 

會話2:

START TRANSACTION; 
INSERT INTO t1 VALUES(1); 

第三節:

START TRANSACTION; 
INSERT INTO t1 VALUES(1); 

會議1:

ROLLBACK; 

The first operation by session 1 acquires an exclusive lock for the row. The operations by sessions 2 and 3 both result in a duplicate-key error and they both request a shared lock for the row. When session 1 rolls back, it releases its exclusive lock on the row and the queued shared lock requests for sessions 2 and 3 are granted. At this point, sessions 2 and 3 deadlock: Neither can acquire an exclusive lock for the row because of the shared lock held by the other.

我有一些問題:

1)插入查詢對它插入的行採用排它鎖。因此,假設T1正在插入第1行,它將鎖定第1行。現在當T2寫入時,INNODB將在執行之前評估該查詢並發現它將寫入相同的PK(i = 1的行)並讓T2等待?或者它會開始執行T2,並發現它給出了重複的鍵錯誤或PK違例。

2)爲什麼T2和T3共享鎖?插入過程中共享鎖如何進入畫面?

+1

添加一些'睡眠(10)'函數調用進行測試的情況下。那麼我們可以進一步討論。包括'SHOW ENGINE INNODB STATUS;'的相關部分。 –

回答

0

1) The insert query takes an exclusive lock on the row it is inserting. So, suppose T1 is inserting on row 1, it will lock row 1. Now when T2 comes to write, will INNODB evaluate the query before executing it and find out that it is going to write the same PK (row with i = 1) and make T2 wait? Or will it start execution of T2 and find that it gives duplicate key error or PK violation.

我認爲你是簡化的術語/過程。在查詢被解析之後,在它被執行之前,它需要獲取必要的鎖。正是在這一點上,確定:

  • 會話1獲取排它鎖,因爲它插入,並且沒有其他鎖
  • 會議2和3 GET排隊等待共享鎖,因爲獨佔鎖已被會話1和會話2日和3是一個重複鍵錯誤

2) Why are T2 and T3 taking shared locks? How do shared locks come into picture during insert?

每以上,會話2和3 GET排隊等待共享鎖,因爲他們是在重複鍵錯誤。但是,當會話1刪除密鑰並釋放排它鎖時,現在會話2和3都會被授予共享鎖。在這一點上都試圖獲得獨佔鎖來完成插入。但是,也不能,因爲另一個已經擁有共享鎖。所以獨佔鎖不授予任何一方,並且它們都是死鎖。

+0

對於你的第一點:他們沒有在緩衝區執行?他們爲什麼排隊等待共享鎖?他們不應該排隊等待IX鎖嗎? –

+0

(1)我不確定你的意思是「在緩衝區中執行」 - 他們必須首先獲得他們需要的鎖。 (2)對於非常可能會出現重複密鑰錯誤的查詢,IX/X鎖定是一種矯枉過正。這更有可能造成更多的死鎖而不是解決。在這裏看到這個確切的討論 - https://bugs.mysql.com/bug.php?id=35821 –

0
  1. 對於會話2和3:INNODB執行,並確定是否該行已經鎖定(其中i行= 1),則交易將等待解鎖隱含行之前評估查詢。

    當你在第一屆會議上插入後執行SHOW ENGINE INNODB STATUS和後運行在會話2和3的刀片:

    ------------ 
    TRANSACTIONS 
    ------------ 
    Trx id counter 2079155 
    Purge done for trx's n:o < 2079150 undo n:o < 0 state: running but idle 
    History list length 594 
    LIST OF TRANSACTIONS FOR EACH SESSION: 
    ---TRANSACTION 2079154, ACTIVE 21 sec inserting 
    mysql tables in use 1, locked 1 
    LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) 
    MySQL thread id 540, OS thread handle 0x7ff989386700, query id 1683 localhost root update 
    INSERT INTO t1 VALUES(1) 
    ------- TRX HAS BEEN WAITING 21 SEC FOR THIS LOCK TO BE GRANTED: 
    RECORD LOCKS space id 4190 page no 3 n bits 72 index `PRIMARY` of table `temp`.`t1` trx id 2079154 lock mode S locks rec but not gap waiting 
    Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
    0: len 4; hex 80000001; asc  ;; 
    1: len 6; hex 0000001fb9af; asc  ;; 
    2: len 7; hex 9c000001d30110; asc  ;; 
    
    ------------------ 
    ---TRANSACTION 2079153, ACTIVE 43 sec inserting 
    mysql tables in use 1, locked 1 
    LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) 
    MySQL thread id 541, OS thread handle 0x7ff989355700, query id 1680 localhost root update 
    INSERT INTO t1 VALUES(1) 
    ------- TRX HAS BEEN WAITING 43 SEC FOR THIS LOCK TO BE GRANTED: 
    RECORD LOCKS space id 4190 page no 3 n bits 72 index `PRIMARY` of table `temp`.`t1` trx id 2079153 lock mode S locks rec but not gap waiting 
    Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
    0: len 4; hex 80000001; asc  ;; 
    1: len 6; hex 0000001fb9af; asc  ;; 
    2: len 7; hex 9c000001d30110; asc  ;; 
    

    解鎖行(回滾從會話1)後,會話2將得到錯誤:ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction ,會話3:Query OK, 1 row affected

  2. 會話2和3沒有共享鎖,它們在隊列中獲得一個,因爲第一個會話的鎖是獨佔的,需要等待。在這種情況下,會話3將獲得一個並插入記錄。

    Shared lock: A kind of lock that allows other transactions to read the locked object, and to also acquire other shared locks on it, but not to write to it. The opposite of exclusive lock.

    Exclusive lock: A kind of lock that prevents any other transaction from locking the same row. Depending on the transaction isolation level, this kind of lock might block other transactions from writing to the same row, or might also block other transactions from reading the same row. The default InnoDB isolation level, REPEATABLE READ, enables higher concurrency by allowing transactions to read rows that have exclusive locks, a technique known as consistent read.

+0

通過邏輯,會話1解鎖行,會話3獲取它,然後在這種情況下,會話2必須獲得鎖超時異常而不是死鎖。 –

+0

超時異常將在配置的超時時間後發生......但如果會話1以回滾或提交結束,則會顯示死鎖錯誤。 –

+0

爲什麼會顯示死鎖?假設Session1完成,會話3獲取鎖定並且既不提交也不回滾,那麼session2應該由於無法獲取鎖定而超時。死鎖將意味着無論會話2和3如果一起運行都不會獲得鎖定。 –

0

問題2:

2)爲什麼T2和T3共享鎖?插入過程中共享鎖如何進入畫面?


它需要對現有條目的鎖,以便後續嘗試插入重複記錄失敗一直