數據庫概論 (八)併發處理

數據庫併發控制

背景:數據庫系統容許多用戶操做,因此同一時間處理的事務可能多大上百個,所以必需要引入併發控制來保證數據的可靠性。數據庫

在併發環境下,事務的隔離性很難保證,所以會出現不少併發一致性問題。併發

丟失修改

丟失修改指一個事務的更新操做被另一個事務的更新操做替換。通常在現實生活中常會遇到,例如:T1 和 T2 兩個事務都對一個數據進行修改,T1 先修改並提交生效,T2 隨後修改,T2 的修改覆蓋了 T1 的修改。3d

讀髒數據

讀髒數據指在不一樣的事務下,當前事務能夠讀到另外事務未提交的數據。例如:T1 修改一個數據但未提交,T2 隨後讀取這個數據。若是 T1 撤銷了此次修改,那麼 T2 讀取的數據是髒數據。對象

不可重複讀

不可重複讀指在一個事務內屢次讀取同一數據集合。在這一事務還未結束前,另外一事務也訪問了該同一數據集合並作了修改,因爲第二個事務的修改,第一次事務的兩次讀取的數據可能不一致。例如:T2 讀取一個數據,T1 對該數據作了修改。若是 T2 再次讀取這個數據,此時讀取的結果和第一次讀取的結果不一樣。blog

幻影讀

幻讀本質上也屬於不可重複讀的狀況,T1 讀取某個範圍的數據,T2 在這個範圍內插入新的數據,T1 再次讀取這個範圍的數據,此時讀取的結果和和第一次讀取的結果不一樣。繼承


產生併發不一致性問題的主要緣由是破壞了事務的隔離性,解決方法是經過併發控制來保證隔離性。併發控制能夠經過封鎖來實現,可是封鎖操做須要用戶本身控制,至關複雜。數據庫管理系統提供了事務的隔離級別,讓用戶以一種更輕鬆的方式處理併發一致性問題。圖片

併發控制機制的任務

  • 保證事務的隔離性 Isolation
  • 對併發操做進行正確的,高效的調度
  • 保證數據庫的一致性

數據庫一致性(Database Consistency)是指事務執行的結果必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。保證數據庫一致性是指當事務完成時,必須使全部數據都具備一致的狀態。在關係型數據庫中,全部的規則必須應用到事務的修改上,以便維護全部數據的完整性。事務

併發控制的主要技術

  • 封鎖機制
  • 時間戳 Timestamp
  • 樂觀控制法

數據庫中的鎖

讀寫鎖

  • 互斥鎖(Exclusive),簡寫爲 X 鎖,又稱寫鎖。
  • 共享鎖(Shared),簡寫爲 S 鎖,又稱讀鎖。

有如下兩個規定:資源

  • 一個事務對數據對象 A 加了 X 鎖,就能夠對 A 進行讀取更新。加鎖期間其它事務不能對 A 加任何鎖。保證其餘事務 在此期間沒法讀取和修改A。
  • 一個事務對數據對象 A 加了 S 鎖,能夠對 A 進行讀取操做,可是不能進行更新操做。加鎖期間其它事務能對 A 加 S 鎖,可是不能加 X 鎖。由於X鎖是互斥鎖,與其餘的任何鎖都互斥,因此加不了。

鎖的兼容關係以下:io

意向鎖

使用意向鎖(Intention Locks)能夠更容易地支持多粒度封鎖。

在存在行級鎖和表級鎖的狀況下,事務 T 想要對錶 A 加 X 鎖,就須要先檢測是否有其它事務對錶 A 或者表 A 中的任意一行加了鎖,那麼就須要對錶 A 的每一行都檢測一次,這是很是耗時的。

IS鎖

若是要對一個數據對象加上IS鎖,那就表明準備向它的後裔節點加上S鎖,例如若是要對R1中某個元組加S鎖,則要首先對關係R1和數據庫加IS鎖 。

IX鎖

若是要對一個數據對象加IX鎖,就表明準備要對它的後裔節點加上X鎖。例如要對R1中某個元組加X鎖,則要首先對關係R1和數據庫加IX鎖。

SIX鎖

SIX鎖爲S鎖加上一個IX鎖,也就是想要讀整個表,並向對其中的一些數據進行修改,這個鎖稍強於除X互斥鎖之外的其餘鎖。


意向鎖在原來的 X/S 鎖之上引入了 IX/IS,IX/IS 都是表鎖,用來表示一個事務想要在表中的某個數據行上加 X 鎖或 S 鎖。有如下兩個規定:

  • 一個事務在得到某個數據行對象的 S 鎖以前,必須先得到表的 IS 鎖或者更強的鎖;
  • 一個事務在得到某個數據行對象的 X 鎖以前,必須先得到表的 IX 鎖。

經過引入意向鎖,事務 T 想要對錶 A 加 X 鎖,只須要先檢測是否有其它事務對錶 A 加了 X/IX/S/IS 鎖,若是加了就表示有其它事務正在使用這個表或者表中某一行的鎖,所以事務 T 加 X 鎖失敗。

各類鎖的兼容關係以下:

image-20210104202159917

解釋以下:

  • 任意 IS/IX 鎖之間都是兼容的,由於它們只表示想要對錶加鎖,而不是真正加鎖
  • 這裏兼容關係針對的是表級鎖,而表級的 IX 鎖和行級的 X 鎖兼容,兩個事務能夠對兩個數據行加 X 鎖。(事務 T1 想要對數據行 R1 加 X 鎖,事務 T2 想要對同一個表的數據行 R2 加 X 鎖,兩個事務都須要對該表加 IX 鎖,可是 IX 鎖是兼容的,而且 IX 鎖與行級的 X 鎖也是兼容的,所以兩個事務都能加鎖成功,對同一個表中的兩個數據行作修改。)

各類鎖的偏序圖

image-20210104155830750

封鎖協議

三級封鎖協議

一級封鎖協議

事務 T 要修改數據 A 時必須加 X 鎖,直到 T 結束才釋放鎖。

能夠解決丟失修改問題,由於不能同時有兩個事務對同一個數據進行修改,那麼事務的修改就不會被覆蓋。

二級封鎖協議

在一級的基礎上,要求讀取數據 A 時必須加 S 鎖,讀取完立刻釋放 S 鎖

能夠解決讀髒數據問題,由於若是一個事務在對數據 A 進行修改,根據 1 級封鎖協議,會加 X 鎖,那麼就不能再加 S 鎖了,也就是不會讀入數據。

三級封鎖協議

在二級的基礎上,要求讀取數據 A 時必須加 S 鎖,直到事務結束了才能釋放 S 鎖

能夠解決不可重複讀的問題,由於讀 A 時,其它事務不能對 A 加 X 鎖,從而避免了在讀的期間數據發生改變。

三個封鎖協議的區別
  • 一級只要求加X鎖,對讀取並不作要求,因此只解決了提交丟失的問題
  • 二級要求在讀取的時候添加S鎖,並在讀取以後當即釋放
  • 三級則要求S鎖的釋放時機在整個事務提交以後
  • 全部高級封鎖協議都基於低一級的封鎖協議

兩段鎖協議

加鎖和解鎖分爲兩個階段進行。

使用兩段封鎖協議的緣由:若是不使用封鎖,或者光對併發執行的事務加鎖,對鎖的申請和釋放時間卻不加控制,就不能保證事務執行的可串行性,數據庫的一致狀態仍有可能被破壞。

  • 在對任何數據進行讀、寫操做以前,事務首先要得到對該數據的封鎖;
  • 在釋放一個封鎖以後,事務再也不申請和得到任何其餘封鎖。

擴展階段就是加鎖的過程,收縮階段就是釋放鎖的過程。

image-20210104200922030
可串行化調度

是指經過併發控制,使得併發執行的事務結果與某個串行執行的事務結果相同。串行執行的事務互不干擾,不會出現併發一致性問題。

舉例
image-20210104200713899
可串行性

是併發事務正確調度的準則, 一個給定的併發調度,當且僅當它是可串行化的,才能被認定爲是正確調度。

事務遵循兩段鎖協議是保證可串行化調度的充分條件。例如如下操做知足兩段鎖協議,它是可串行化調度。

lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
但不是必要條件,例如如下操做不知足兩段鎖協議,但它仍是可串行化調度。

lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)

若併發的事務都遵照2PL, 則這些事務的任何併發調度都是可串行化的。

一次封鎖協議能夠避免死鎖的發生,可是遵循兩端鎖協議有可能發生死鎖,由於上鎖並非一塊兒完成的,在未上鎖的時候,其中一個須要的數據被其餘的事務拿到了鎖,致使本來的事務沒辦法拿到鎖,致使死鎖的發生。

image-20210104201331271
衝突操做

指的是不一樣的事務對同一個數據的讀寫操做和寫寫操做。

一個讀一個寫,那麼狀態就不一致了,兩個寫操做也會致使數據庫狀態丟失、不一致

image-20210104200630277

衝突可串行化

可串行化操做的充分條件:

  • 一個調度Sc在保證衝突操做的次序不變的狀況下,經過交換兩個事務不衝突操做的次序獲得另外一個調度Sc',若是Sc'是串行的,稱調度Sc爲衝突可串行化的調度
  • 一個調度是衝突可串行化,必定是可串行化的調度

嚴格兩段鎖協議

除了要求知足兩段鎖協議規定以外,還要求事務的排他鎖必需要在事務提交以後釋放。

能夠解決髒數據的讀取問題。

強兩段鎖協議

要求在知足兩段鎖協議以外,全部的鎖都要在事務提交以後釋放。

事務能夠按照其提交的順序完成串行化。

封鎖粒度

MySQL 中提供了兩種封鎖粒度:行級鎖以及表級鎖。

應該儘可能只鎖定須要修改的那部分數據,而不是全部的資源。鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。

可是加鎖須要消耗資源,鎖的各類操做(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增長系統開銷。所以封鎖粒度越小,系統開銷就越大。

在選擇封鎖粒度時,須要在鎖開銷和併發程度之間作一個權衡。

粒度樹

image-20210104201720916
  • 容許多粒度樹中的每一個節點被獨立的加鎖
  • 一個節點被加了鎖意味着這個節點之下全部的子節點都要被加上相同類型的鎖
  • 因此有兩種加鎖的方式
    • 顯示加鎖,也就是直接指定加鎖的粒度範圍
    • 隱示加鎖,從父節點那裏繼承、傳遞下來的相同類型的鎖

因此係統在檢查一個數據對象是否有鎖的時候不只要檢查有沒有顯示的加上鎖,還要檢查其上級節點有沒有被加上鎖。同時也不能忘了檢查其子節點有沒有鎖與即將要加上的鎖衝突,若是出現衝突也不能上鎖。

部分圖片與文字資料來自CS-Note

相關文章
相關標籤/搜索