MySQL在預設事務下各SQL語句使用的鎖分析

FrankYou發表於2018-09-07

 資料庫使用鎖是為了支援更好的併發,提供資料的完整性和一致性。InnoDB是一個支援行鎖的儲存引擎,鎖的型別有:共享鎖(S)、排他鎖(X)、意向共享(IS)、意向排他(IX)。為了提供更好的併發,InnoDB提供了非鎖定讀:不需要等待訪問行上的鎖釋放,讀取行的一個快照。該方法是通過InnoDB的一個特性:MVCC來實現的

InnoDB有三種行鎖的演算法:

1,Record Lock:單個行記錄上的鎖。

2,Gap Lock:間隙鎖,鎖定一個範圍,但不包括記錄本身。GAP鎖的目的,是為了防止同一事務的兩次當前讀,出現幻讀的情況。

3,Next-Key Lock:1+2,鎖定一個範圍,並且鎖定記錄本身。對於行的查詢,都是採用該方法,主要目的是解決幻讀的問題。

如果採用MySQL預設的事務隔離級別(可以重複讀:repeatable read

可重複讀取(Repeatable Read):防止(避免)不可重複讀取和髒讀,但是有時可能出現幻讀資料。這可以通過“共享讀鎖”和“排他寫鎖”實現。讀取資料的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。

  • 髒讀:一個事務還未提交,另外一個事務訪問此事務修改的資料,並使用,讀取了事務中間狀態資料。
  • 幻讀:一個事務讀取2次,得到的記錄條數不一致,由於2次讀取之間另外一個事務對資料進行了增刪。
  • 不可重複讀:一個事務讀取同一條記錄2次,得到的結果不一致,由於在2次讀取之間另外一個事務對此行資料進行了修改。

1.SELECT ... FROM

  >是一個快照讀,通過讀取資料庫的一個快照,不會加任何鎖,除非將隔離級別設定成了 SERIALIZABLE 。

2.SELECT ... FROM ... LOCK IN SHARE MODE

>在所有索引掃描範圍的索引記錄上加上共享的next key鎖;如果是唯一索引,只需要在相應記錄上加index record lock。這些被共享lock住的行無法進行update/delete。
>允許其它事務對這些記錄再加SHARE鎖
>如果沒有使用到索引,則鎖住全表(表級的排他鎖),無法進行insert/update/delete。

3.SELECT ... FROM ... FOR UPDATE

>在所有索引掃描範圍的索引記錄上加上排他的next key鎖。如果是唯一索引,只需要在相應記錄上加index record lock。
>如果沒有利用到索引將鎖住全表(表級的排他鎖),其它事務無法進行insert/update/delete操作。

4. UPDATE ... WHERE ...

>在所有索引掃描範圍的索引記錄上加上排他的next key鎖。如果是唯一索引,只需要在相應記錄上加index record lock。
>如果沒有利用到索引將鎖住全表(表級的排他鎖),其它事務無法進行其他的insert/update/delete操作。;

5. DELETE FROM ... WHERE ...

>語句在所有索引掃描範圍的索引記錄上加上排他的next key鎖。如果是唯一索引,只需要在相應記錄上加index record lock。
>如果沒有利用到索引將鎖住全表(表級的排他鎖),其它事務無法進行其它的insert/update/delete操作。

6. INSERT

>在插入的記錄上加一把排他鎖,這個鎖是一個index-record lock,並不是next-key 鎖,因此就沒有gap 鎖,他將不會阻止其他會話在該條記錄之前的gap插入記錄。

 

總結:

隔離級別越高,越能保證資料的完整性和一致性,但是對併發效能的影響也越大,魚和熊掌不可兼得啊。對於多數應用程式,可以優先考慮把資料庫系統的隔離級別設為Read Committed它能夠避免髒讀取,而且具有較好的併發效能。儘管它會導致不可重複讀、幻讀這些併發問題,在可能出現這類問題的個別場合,可以由應用程式採用悲觀鎖或樂觀鎖來控制。

相關文章