數據庫使用鎖是為了支持更好的並發,提供數據的完整性和一致性。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,它能夠避免臟讀取,而且具有較好的並發性能。盡管它會導致不可重復讀、幻讀這些並發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。