MySQL 加鎖和死鎖解析



產生死鎖的必要條件

  • 多個併發事務(2個或者以上)
  • 每一個事物都持有了鎖(或者是已經在等待鎖)
  • 每一個事務都須要再繼續持有鎖(爲了完成事務邏輯,還必須更新更多的行)
  • 事物之間產生加鎖的循環等待,造成死鎖this

    常規鎖模式

  • LOCK_S(讀鎖,共享鎖)
  • LOCK_X(寫鎖,排它鎖)code

    鎖的屬性

  • LOCK _REC_NOT_GAP(鎖記錄)
  • LOCK_GAP(鎖記錄前的GAP)
  • LOCK_ORDINARY(同時鎖記錄+記錄前的GAP,Next key鎖)
  • LOCK_INSERT_INTETION(插入意向鎖)blog

    鎖組合(屬性+模式)

    能夠任意組合索引

    鎖衝突矩陣

鎖是加在那裏的?

  • 根據主鍵查找-鎖加在主鍵上
    如 begin;select * from tt_copy where id=4 for update;
    加鎖狀況事務

    index PRIMARY of table test.tt_copy trx id 1101588 lock_mode X locks rec but not gapit

  • 根據普通索引查找-鎖加在普通索引和主鍵上
    如 begin;select * from tt_copy force index(idx_a) where a=4 for update;
    加鎖狀況io

    index idx_a of table test.tt_copy trx id 1101590 lock_mode X locks rec but not gap
    index PRIMARY of table test.tt_copy trx id 1101590 lock_mode X locks rec but not gapinnodb

操做與加鎖的對照關係

如下沒特殊說明都爲RC隔離級別event

Insert

  • 無Unique key,插入後 :不管RC或RR隔離級別都是對主鍵加 LOCK_X+LOCK_REC_NOT_GAP
  • 有Unique key

    插入前,惟一約束檢查:LOCK_S+LOCK_ORDINARY
    插入前,插入的位置有GAP鎖:LOCK_INSERT_INTETION
    插入後,新數據插入:LOCK_X+LOCK_REC_NOT_GAP

Delete

知足刪除條件的全部記錄:LOCK_X+LOCK_REC_NOT_GAP

Update

Update操做分解

  • Step 1:定位到 下一條知足查詢條件的記錄(查詢過程,相似於Select/Delete)
  • Step 2:刪除當前定位到的記錄(標記爲刪除狀態)
  • Step 3:拼裝更新後項,根據更新後項定位到 新的插入位置
  • Step 4:在新的插入位置,判斷是否存在 Unique 衝突( 存在Unique Key 時
  • Step 5:插入更新後項(不存在Unique衝突時)
  • Step 6: 重複Step 1 到Step 5 的操做,直至掃描完整個查詢範圍

Update操做分析

  • Step 1,Step 2:Delete
  • Step 3,Step 4,Step 5:Insert

Update

  • 無Unique key:

    • 查詢範圍中的全部記錄,LOCK_X + LOCK_REC_NOT_GAP
  • 有Unique key:

    • 查找知足條件的記錄:查詢範圍內的全部記錄, LOCK_X + LOCK_REC_NOT_GAP
    • 更新後項存在惟一性衝突:衝突項上的加鎖,LOCK_S + LOCK_ORDINARY
    • 更新後項不存在惟一性衝突: 更新位置後項加鎖,LOCK_S + LOCK_GAP (省略)
    • 實際更新操做:可看作插入了一條新紀錄,LOCK_X + LOCK_REC_NOT_GAP

GAP鎖

那些操做會加GAP鎖?

  • Read Committed (RC) ) :Unique Key 惟一約束檢查;Purge操做;
  • Repeatable Read (RC ):RC的基礎上,全部須要加鎖的索引範圍掃描和索引查找(Update/Delete…)
  • 還有一種會加GAP鎖:RR隔離級別下,對有惟一索引的表執行insert on duplicate update操做,除了會對新插入的記錄加x not gap外,還會對相鄰記錄加x gap

如何去掉GAP鎖?

change the transaction isolation level to READ COMMITTED or enable the innodb_locks_unsafe_for_binlog system variable (which is now deprecated)

何時加next-key lock?

By default, InnoDB operates in REPEATABLE READ transaction isolation level. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows

Insert Intention Lock

An insert intention lock is a type of gap lock set by INSERT operations prior to(在...以前) row insertion.

總結

• 原則之一

  • 要分析一個死鎖,必須深刻業務,瞭解整個事務的邏輯(閉門沒法造車)

• 原則之二`

  • GAP鎖很複雜,爲了減小GAP鎖,減小GAP致使的死鎖,儘可能選擇Read Committed隔離級別(RC + row based binlog,基本上可以解決全部問題,無需使用Repeatable Read)
  • 適當的 減小Unique 索引,可以減小GAP鎖致使的死鎖(根據業務狀況而定)

• 原則之三

  • 在MySQL 中,以不一樣索引的過濾條件, 來操做相同的記錄(Update/Delete ),很容易產生死
    鎖。

• 原則之四

  • RC隔離級別下,若是死鎖中出現Next Key(Gap鎖),說明表中必定存在unique索引
  • 多語句事務產生的死鎖,確保每條語句操做記錄的順序性,可以極大減小死鎖

本文大多數都整理自《死鎖-何登成 - 管中窺豹——MySQL(InnoDB)死鎖分析之道》

相關文章
相關標籤/搜索