當前位置:編程學習大全網 - 編程語言 - 關於mySql 中樂觀鎖與讀已提交(事務隔離級別)的搭配使用問題!!求大神帶飛!

關於mySql 中樂觀鎖與讀已提交(事務隔離級別)的搭配使用問題!!求大神帶飛!

術式之後皆為邏輯,壹切皆為需求和實現。希望此文能從需求、現狀和解決方式的角度幫大家理解隔離級別。

隔離級別的產生

在串型執行的條件下,數據修改的順序是固定的、可預期的結果,但是並發執行的情況下,數據的修改是不可預期的,也不固定,為了實現數據修改在並發執行的情況下得到壹個固定、可預期的結果,由此產生了隔離級別。

所以隔離級別的作用是用來平衡數據庫並發訪問與數據壹致性的方法。

事務的4種隔離級別

READ UNCOMMITTED ? 未提交讀,可以讀取未提交的數據。READ COMMITTED 已提交讀,對於鎖定讀(select with for update 或者 for share)、update 和 delete 語句, ? InnoDB 僅鎖定索引記錄,而不鎖定它們之間的間隙,因此允許在鎖定的記錄旁邊自由插入新記錄。 ? Gap locking 僅用於外鍵約束檢查和重復鍵檢查。REPEATABLE READ 可重復讀,事務中的壹致性讀取讀取的是事務第壹次讀取所建立的快照。SERIALIZABLE ? 序列化

在了解了 4 種隔離級別的需求後,在采用鎖控制隔離級別的基礎上,我們需要了解加鎖的對象(數據本身&間隙),以及了解整個數據範圍的全集組成。

數據範圍全集組成

SQL 語句根據條件判斷不需要掃描的數據範圍(不加鎖);

SQL 語句根據條件掃描到的可能需要加鎖的數據範圍;

以單個數據範圍為例,數據範圍全集包含:(數據範圍不壹定是連續的值,也可能是間隔的值組成)

1. 數據已經填充了整個數據範圍:(被完全填充的數據範圍,不存在數據間隙)

整形,對值具有唯壹約束條件的數據範圍 1~5 ,

已有數據1、2、3、4、5,此時數據範圍已被完全填充;

整形,對值具有唯壹約束條件的數據範圍 1 和 5 ,

已有數據1、5,此時數據範圍已被完全填充;?

2. 數據填充了部分數據範圍:(未被完全填充的數據範圍,是存在數據間隙)

整形的數據範圍 1~5 ,

已有數據 1、2、3、4、5,但是因為沒有唯壹約束,

所以數據範圍可以繼續被 1~5 的數據重復填充;

整形,具有唯壹約束條件的數據範圍 1~5 ,

已有數據 2,5,此時數據範圍未被完全填充,還可以填充 1、3、4 ;

3. 數據範圍內沒有任何數據(存在間隙)

如下:

整形的數據範圍 1~5 ,數據範圍內當前沒有任何數據。

在了解了數據全集的組成後,我們再來看看事務並發時,會帶來的問題。

無控制的並發所帶來的問題

並發事務如果不加以控制的話會帶來壹些問題,主要包括以下幾種情況。

1. 範圍內已有數據更改導致的:

更新丟失:當多個事務選擇了同壹行,然後基於最初選定的值更新該行時,

由於每個事物不知道其他事務的存在,最後的更新就會覆蓋其他事務所做的更新;

臟讀: 壹個事務正在對壹條記錄做修改,這個事務完成並提交前,這條記錄就處於不壹致狀態。

這時,另外壹個事務也來讀取同壹條記錄,如果不加控制,

第二個事務讀取了這些“臟”數據,並據此做了進壹步的處理,就會產生提交的數據依賴關系。

這種現象就叫“臟讀”。

2. 範圍內數據量發生了變化導致:

不可重復讀:壹個事務在讀取某些數據後的某個時間,再次讀取以前讀過的數據,

卻發現其讀出的數據已經發生了改變,或者某些記錄已經被刪除了。

這種現象就叫“不可重復讀”。

幻讀:壹個事務按相同的查詢條件重新讀取以前檢索過的數據,

卻發現其他事務插入了滿足其查詢條件的新數據,這種現象稱為“幻讀”。

可以簡單的認為滿足條件的數據量變化了。

因為無控制的並發會帶來壹系列的問題,這些問題會導致無法滿足我們所需要的結果。因此我們需要控制並發,以實現我們所期望的結果(隔離級別)。

MySQL 隔離級別的實現

InnoDB 通過加鎖的策略來支持這些隔離級別。

行鎖包含:

Record Locks

索引記錄鎖,索引記錄鎖始終鎖定索引記錄,即使表中未定義索引,

這種情況下,InnoDB 創建壹個隱藏的聚簇索引,並使用該索引進行記錄鎖定。

Gap Locks

間隙鎖是索引記錄之間的間隙上的鎖,或者對第壹條記錄之前或者最後壹條記錄之後的鎖。

間隙鎖是性能和並發之間權衡的壹部分。

對於無間隙的數據範圍不需要間隙鎖,因為沒有間隙。

Next-Key Locks

索引記錄上的記錄鎖和索引記錄之前的 gap lock 的組合。

假設索引包含 10、11、13 和 20。

可能的next-key locks包括以下間隔,其中圓括號表示不包含間隔端點,方括號表示包含端點:

(負無窮大, 10] (10, 11] (11, 13] (13, 20] (20, 正無窮大) 對於最後壹個間隔,next-key將會鎖定索引中最大值的上方,

左右滑動進行查看

"上確界"偽記錄的值高於索引中任何實際值。

上確界不是壹個真正的索引記錄,因此,實際上,這個 next-key 只鎖定最大索引值之後的間隙。

基於此,當獲取的數據範圍中,數據已填充了所有的數據範圍,那麽此時是不存在間隙的,也就不需要 gap lock。

對於數據範圍內存在間隙的,需要根據隔離級別確認是否對間隙加鎖。

默認的 REPEATABLE READ 隔離級別,為了保證可重復讀,除了對數據本身加鎖以外,還需要對數據間隙加鎖。

READ COMMITTED 已提交讀,不匹配行的記錄鎖在 MySQL 評估了 where 條件後釋放。

對於 update 語句,InnoDB 執行 "semi-consistent" 讀取,這樣它會將最新提交的版本返回到 MySQL,

以便 MySQL 可以確定該行是否與 update 的 where 條件相匹配。

總結&延展:

唯壹索引存在唯壹約束,所以變更後的數據若違反了唯壹約束的原則,則會失敗。

當 where 條件使用二級索引篩選數據時,會對二級索引命中的條目和對應的聚簇索引都加鎖;所以其他事務變更命中加鎖的聚簇索引時,都會等待鎖。

行鎖的增加是壹行壹行增加的,所以可能導致並發情況下死鎖的發生。

例如,

在 session A 對符合條件的某聚簇索引加鎖時,可能 session B 已持有該聚簇索引的 Record Locks,而 session B 正在等待 session A 已持有的某聚簇索引的 Record Locks。

session A 和 session B 是通過兩個不相幹的二級索引定位到的聚簇索引。

session A 通過索引 idA,session B通過索引 idB 。

當 where 條件獲取的數據無間隙時,無論隔離級別為 rc 或 rr,都不會存在間隙鎖。

比如通過唯壹索引獲取到了已完全填充的數據範圍,此時不需要間隙鎖。

間隙鎖的目的在於阻止數據插入間隙,所以無論是通過 insert 或 update 變更導致的間隙內數據的存在,都會被阻止。

rc 隔離級別模式下,查詢和索引掃描將禁用 gap locking,此時 gap locking 僅用於外鍵約束檢查和重復鍵檢查(主要是唯壹性檢查)。

rr 模式下,為了防止幻讀,會加上 Gap Locks。

事務中,SQL 開始則加鎖,事務結束才釋放鎖。

就鎖類型而言,應該有優化鎖,鎖升級等,例如rr模式未使用索引查詢的情況下,是否可以直接升級為表鎖。

就鎖的應用場景而言,在回放場景中,如果確定事務可並發,則可以考慮不加鎖,加快回放速度。

鎖只是並發控制的壹種粒度,只是壹個很小的部分:

從不同場景下是否需要控制並發,(已知無交集且有序的數據的變更,MySQL 的 MTS 相同前置事務的多事務並發回放)

並發控制的粒度,(鎖是壹種邏輯粒度,可能還存在物理層和其他邏輯粒度或方式)

相同粒度下的優化,(鎖本身存在優化,如IX、IS類型的優化鎖)

粒度加載的安全&性能(如獲取行鎖前,先獲取頁鎖,頁鎖在執行獲取行鎖操作後即釋放,無論是否獲取成功)等多個層次去思考並發這玩意。

  • 上一篇:java工程師需要具備哪些技能,怎樣考證
  • 下一篇:社區網格化管理實施方案
  • copyright 2024編程學習大全網