資料庫并發控制
背景:資料庫系統允許多用戶操作,所以同一時間處理的事務可能多大上百個,因此必須要引入并發控制來保證資料的可靠性,
在并發環境下,事務的隔離性很難保證,因此會出現很多并發一致性問題,
丟失修改
丟失修改指一個事務的更新操作被另外一個事務的更新操作替換,一般在現實生活中常會遇到,例如:T1 和 T2 兩個事務都對一個資料進行修改,T1 先修改并提交生效,T2 隨后修改,T2 的修改覆寫了 T1 的修改,

讀臟資料
讀臟資料指在不同的事務下,當前事務可以讀到另外事務未提交的資料,例如:T1 修改一個資料但未提交,T2 隨后讀取這個資料,如果 T1 撤銷了這次修改,那么 T2 讀取的資料是臟資料,

不可重復讀
不可重復讀指在一個事務內多次讀取同一資料集合,在這一事務還未結束前,另一事務也訪問了該同一資料集合并做了修改,由于第二個事務的修改,第一次事務的兩次讀取的資料可能不一致,例如:T2 讀取一個資料,T1 對該資料做了修改,如果 T2 再次讀取這個資料,此時讀取的結果和第一次讀取的結果不同,

幻影讀
幻讀本質上也屬于不可重復讀的情況,T1 讀取某個范圍的資料,T2 在這個范圍內插入新的資料,T1 再次讀取這個范圍的資料,此時讀取的結果和和第一次讀取的結果不同,

產生并發不一致性問題的主要原因是破壞了事務的隔離性,解決方法是通過并發控制來保證隔離性,并發控制可以通過封鎖來實作,但是封鎖操作需要用戶自己控制,相當復雜,資料庫管理系統提供了事務的隔離級別,讓用戶以一種更輕松的方式處理并發一致性問題,
并發控制機制的任務
- 保證事務的隔離性 Isolation
- 對并發操作進行正確的,高效的調度
- 保證資料庫的一致性
資料庫一致性(Database Consistency)是指事務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態,保證資料庫一致性是指當事務完成時,必須使所有資料都具有一致的狀態,在關系型資料庫中,所有的規則必須應用到事務的修改上,以便維護所有資料的完整性,
并發控制的主要技術
- 封鎖機制
- 時間戳 Timestamp
- 樂觀控制法
資料庫中的鎖
讀寫鎖
- 互斥鎖(Exclusive),簡寫為 X 鎖,又稱寫鎖,
- 共享鎖(Shared),簡寫為 S 鎖,又稱讀鎖,
有以下兩個規定:
- 一個事務對資料物件 A 加了 X 鎖,就可以對 A 進行讀取和更新,加鎖期間其它事務不能對 A 加任何鎖,保證其他事務 在此期間無法讀取和修改A,
- 一個事務對資料物件 A 加了 S 鎖,可以對 A 進行讀取操作,但是不能進行更新操作,加鎖期間其它事務能對 A 加 S 鎖,但是不能加 X 鎖,因為X鎖是互斥鎖,與其他的任何鎖都互斥,所以加不了,
鎖的兼容關系如下:

意向鎖
使用意向鎖(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 鎖失敗,
各種鎖的兼容關系如下:

解釋如下:
- 任意 IS/IX 鎖之間都是兼容的,因為它們只表示想要對表加鎖,而不是真正加鎖;
- 這里兼容關系針對的是表級鎖,而表級的 IX 鎖和行級的 X 鎖兼容,兩個事務可以對兩個資料行加 X 鎖,(事務 T1 想要對資料行 R1 加 X 鎖,事務 T2 想要對同一個表的資料行 R2 加 X 鎖,兩個事務都需要對該表加 IX 鎖,但是 IX 鎖是兼容的,并且 IX 鎖與行級的 X 鎖也是兼容的,因此兩個事務都能加鎖成功,對同一個表中的兩個資料行做修改,)
各種鎖的偏序圖
封鎖協議
三級封鎖協議
一級封鎖協議
事務 T 要修改資料 A 時必須加 X 鎖,直到 T 結束才釋放鎖,
可以解決丟失修改問題,因為不能同時有兩個事務對同一個資料進行修改,那么事務的修改就不會被覆寫,

二級封鎖協議
在一級的基礎上,要求讀取資料 A 時必須加 S 鎖,讀取完馬上釋放 S 鎖,
可以解決讀臟資料問題,因為如果一個事務在對資料 A 進行修改,根據 1 級封鎖協議,會加 X 鎖,那么就不能再加 S 鎖了,也就是不會讀入資料,

三級封鎖協議
在二級的基礎上,要求讀取資料 A 時必須加 S 鎖,直到事務結束了才能釋放 S 鎖,
可以解決不可重復讀的問題,因為讀 A 時,其它事務不能對 A 加 X 鎖,從而避免了在讀的期間資料發生改變,

三個封鎖協議的區別
- 一級只要求加X鎖,對讀取并不做要求,所以只解決了提交丟失的問題
- 二級要求在讀取的時候添加S鎖,并在讀取之后立即釋放
- 三級則要求S鎖的釋放時機在整個事務提交之后
- 所有高級封鎖協議都基于低一級的封鎖協議
兩段鎖協議
加鎖和解鎖分為兩個階段進行,
使用兩段封鎖協議的原因:如果不使用封鎖,或者光對并發執行的事務加鎖,對鎖的申請和釋放時間卻不加控制,就不能保證事務執行的可串行性,資料庫的一致狀態仍有可能被破壞,
- 在對任何資料進行讀、寫操作之前,事務首先要獲得對該資料的封鎖;
- 在釋放一個封鎖之后,事務不再申請和獲得任何其他封鎖,
擴展階段就是加鎖的程序,收縮階段就是釋放鎖的程序,
可串行化調度
是指通過并發控制,使得并發執行的事務結果與某個串行執行的事務結果相同,串行執行的事務互不干擾,不會出現并發一致性問題,
舉例
可串行性
是并發事務正確調度的準則, 一個給定的并發調度,當且僅當它是可串行化的,才能被認定為是正確調度,
事務遵循兩段鎖協議是保證可串行化調度的充分條件,例如以下操作滿足兩段鎖協議,它是可串行化調度,
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, 則這些事務的任何并發調度都是可串行化的,
一次封鎖協議可以避免死鎖的發生,但是遵循兩端鎖協議有可能發生死鎖,因為上鎖并不是一起完成的,在未上鎖的時候,其中一個需要的資料被其他的事務拿到了鎖,導致原本的事務沒辦法拿到鎖,導致死鎖的發生,
沖突操作
指的是不同的事務對同一個資料的讀寫操作和寫寫操作,
一個讀一個寫,那么狀態就不一致了,兩個寫操作也會導致資料庫狀態丟失、不一致
沖突可串行化
可串行化操作的充分條件:
- 一個調度Sc在保證沖突操作的次序不變的情況下,通過交換兩個事務不沖突操作的次序得到另一個調度Sc',如果Sc'是串行的,稱調度Sc為沖突可串行化的調度
- 一個調度是沖突可串行化,一定是可串行化的調度
嚴格兩段鎖協議
除了要求滿足兩段鎖協議規定之外,還要求事務的排他鎖必須要在事務提交之后釋放,
可以解決臟資料的讀取問題,
強兩段鎖協議
要求在滿足兩段鎖協議之外,所有的鎖都要在事務提交之后釋放,
事務可以按照其提交的順序完成串行化,
封鎖粒度
MySQL 中提供了兩種封鎖粒度:行級鎖以及表級鎖,
應該盡量只鎖定需要修改的那部分資料,而不是所有的資源,鎖定的資料量越少,發生鎖爭用的可能就越小,系統的并發程度就越高,
但是加鎖需要消耗資源,鎖的各種操作(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增加系統開銷,因此封鎖粒度越小,系統開銷就越大,
在選擇封鎖粒度時,需要在鎖開銷和并發程度之間做一個權衡,
粒度樹
- 允許多粒度樹中的每個節點被獨立的加鎖
- 一個節點被加了鎖意味著這個節點之下所有的子節點都要被加上相同型別的鎖
- 所以有兩種加鎖的方式
- 顯示加鎖,也就是直接指定加鎖的粒度范圍
- 隱示加鎖,從父節點那里繼承、傳遞下來的相同型別的鎖
所以系統在檢查一個資料物件是否有鎖的時候不僅要檢查有沒有顯示的加上鎖,還要檢查其上級節點有沒有被加上鎖,同時也不能忘了檢查其子節點有沒有鎖與即將要加上的鎖沖突,如果出現沖突也不能上鎖,
部分圖片與文字資料來自CS-Note
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/248954.html
標籤:MySQL
上一篇:資料庫概論 (七)恢復技術
