簡介
1. 多用戶數據庫系統
允許多個用戶同時使用的數據庫系統
-飛機定票數據庫系統
- 銀行數據庫系統
- 特點:在同一時刻併發運行的事務數可達數百上千個
2.多事務執行方式
2.1 事務串行執行
- 每個時刻只有一個事務運行,其他事務必須等到這個事務結束以後方能運行
- 不能充分利用系統資源,發揮數據庫共享資源的特點
2.2 交叉併發方式(Interleaved Concurrency)
- 在單處理機系統中,事務的並行執行是這些並行事務的並行操作輪流交叉運行
- 單處理機系統中的並行事務並沒有真正地並行運行,但能夠減少處理機的空閒時間,提高系統的效率
2.3同時併發方式(simultaneous concurrency)
- 多處理機系統中,每個處理機可以運行一個事務,多個處理機可以同時運行多個事務,實現多個事務真正的並行運行
- 最理想的併發方式,但受制於硬件環境
- 更復雜的併發方式機制
本章討論的數據庫系統併發控制技術是以單處理機系統爲基礎的
2.4 事務併發執行帶來的問題
- 會產生多個事務同時存取同一數據的情況
- 可能會存取和存儲不正確的數據,破壞事務隔離性和數據庫的一致性
數據庫管理系統必須提供併發控制機制
併發控制機制是衡量一個數據庫管理系統性能的重要標誌之一
1 併發控制概述
事務是併發控制的基本單位
併發控制機制的任務
- 對併發操作進行正確調度
- 保證事務的隔離性
- 保證數據庫的一致性
併發操作帶來數據的不一致性實例
[例11.1]飛機訂票系統中的一個活動序列
① 甲售票點(事務T1)讀出某航班的機票餘額A,設A=16;
② 乙售票點(事務T2)讀出同一航班的機票餘額A,也爲16;
③ 甲售票點賣出一張機票,修改餘額A←A-1,所以A爲15,把A寫回數據庫;
④ 乙售票點也賣出一張機票,修改餘額A←A-1,所以A爲15,把A寫回數據庫
結果明明賣出兩張機票,數據庫中機票餘額只減少1
- 這種情況稱爲數據庫的不一致性,是由併發操作引起的。
- 在併發操作情況下,對T1、T2兩個事務的操作序列的調度是隨機的。
- 若按上面的調度序列執行,T1事務的修改就被丟失。
- 原因:第4步中T2事務修改A並寫回後覆蓋了T1事務的修改
併發操作帶來的數據不一致性
- 1.丟失修改(Lost Update)
- 2.不可重複讀(Non-repeatable Read)
- 3.讀“髒”數據(Dirty Read)
記號
- R(x):讀數據x
- W(x):寫數據x
1.1修改丟失
兩個事務T1和T2讀入同一數據並修改,T2的提交結果破壞了T1提交的結果,導致T1的修改被丟失。
上面飛機訂票例子就屬此類
1.2 不可重複讀
不可重複讀是指事務T1讀取數據後,事務T2 執行更新操作,使T1無法再現前一次讀取結果。
不可重複讀包括三種情況:
- 1.事務T1讀取某一數據後,事務T2對其做了修改,當事務T1再次讀該數據時,得到與前一次不同的值
- T1讀取B=100進行運算
- T2讀取同一數據B,對其進行修改後將B=200寫回數據庫。
- T1爲了對讀取值校對重讀B,B已爲200,與第一次讀取值不一致
- 2.事務T1按一定條件從數據庫中讀取了某些數據記錄後,事務T2刪除了其中部分記錄,當T1再次按相同條件讀取數據時,發現某些記錄神祕地消失了。
- 3.事務T1按一定條件從數據庫中讀取某些數據記錄後,事務T2插入了一些記錄,當T1再次按相同條件讀取數據時,發現多了一些記錄。
後兩種不可重複讀有時也稱爲幻影現象(Phantom Row)
1.3 讀“髒”數據
- 事務T1修改某一數據,並將其寫回磁盤
- 事務T2讀取同一數據後,T1由於某種原因被撤銷
- 這時T1已修改過的數據恢復原值,T2讀到的數據就與數據庫中的數據不一致
- T2讀到的數據就爲“髒”數據,即不正確的數據
- T1將C值修改爲200,T2讀到C爲200
- T1由於某種原因撤銷,其修改作廢,C恢復原值100
- 這時T2讀到的C爲200,與數據庫內容不一致,就是“髒”數據
數據不一致性:由於併發操作破壞了事務的隔離性
併發控制就是要用正確的方式調度併發操作,使一個用戶事務的執行不受其他事務的干擾,從而避免造成數據的不一致性
對數據庫的應用有時允許某些不一致性,例如有些統計工作涉及數據量很大,讀到一些“髒”數據對統計精度沒什麼影響,可以降低對一致性的要求以減少系統開銷
併發控制的主要技術
- 封鎖(Locking)
- 時間戳(Timestamp)
- 樂觀控制法
- 多版本併發控制(MVCC)
2 封鎖
2.1什麼是封鎖
- 封鎖就是事務T在對某個數據對象(例如表、記錄等)操作之前,先向系統發出請求,對其加鎖
- 加鎖後事務T就對該數據對象有了一定的控制,在事務T釋放它的鎖之前,其它的事務不能更新此數據對象。
- 封鎖是實現併發控制的一個非常重要的技術
2.2基本封鎖類型
一個事務對某個數據對象加鎖後究竟擁有什麼樣的控制由封鎖的類型決定。
基本封鎖類型
-
排它鎖(Exclusive Locks,簡記爲X鎖)
排它鎖又稱爲寫鎖
若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖
保證其他事務在T釋放A上的鎖之前不能再讀取和修改A -
共享鎖(Share Locks,簡記爲S鎖)
共享鎖又稱爲讀鎖
若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其它事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖
保證其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改
2.3鎖的相容矩陣
Y=Yes,相容的請求(可同時進行)
N=No,不相容的請求(不可同時進行)
在鎖的相容矩陣中:
最左邊一列表示事務T1已經獲得的數據對象上的鎖的類型,其中橫線表示沒有加鎖。
最上面一行表示另一事務T2對同一數據對象發出的封鎖請求。
- T2的封鎖請求能否被滿足用矩陣中的Y和N表示
- Y表示事務T2的封鎖要求與T1已持有的鎖相容,封鎖請求可以滿足
- N表示T2的封鎖請求與T1已持有的鎖衝突,T2的請求被拒絕
3 封鎖協議
3.1什麼是封鎖協議
- 在運用X鎖和S鎖對數據對象加鎖時,需要約定一些規則,這些規則爲封鎖協議(Locking Protocol)。
- 何時申請X鎖或S鎖
- 持鎖時間
- 何時釋放
- 對封鎖方式規定不同的規則,就形成了各種不同的封鎖協議,它們分別在不同的程度上爲併發操作的正確調度提供一定的保證。
3.2三級封鎖協議
3.2.1. 一級封鎖協議
事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放。
- 正常結束(COMMIT)
- 非正常結束(ROLLBACK)
一級封鎖協議可防止丟失修改,並保證事務T是可恢復的。
在一級封鎖協議中,如果僅僅是讀數據不對其進行修改,是不需要加鎖的,所以它不能保證可重複讀和不讀“髒”數據。
使用封鎖機制解決丟失修改問題
- 事務T1在讀A進行修改之前先對A加X鎖
- 當T2再請求對A加X鎖時被拒絕
- T2只能等待T1釋放A上的鎖後獲得對A的X鎖
- 這時T2讀到的A已經是T1更新過的值15
- T2按此新的A值進行運算,並將結果值A=14寫回到磁盤。避免了丟失T1的更新。
3.2.2. 二級封鎖協議
-
一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完後即可釋放S鎖。
-
二級封鎖協議可以防止丟失修改和讀“髒”數據。
-
在二級封鎖協議中,由於讀完數據後即可釋放S鎖,所以它不能保證可重複讀。
使用封鎖機制解決讀“髒”數據問題
- 事務T1在對C進行修改之前,先對C加X鎖,修改其值後寫回磁盤
- T2請求在C上加S鎖,因T1已在C上加了X鎖,T2只能等待
- T1因某種原因被撤銷,C恢復爲原值100
- T1釋放C上的X鎖後T2獲得C上的S鎖,讀C=100。避免了T2讀“髒”數據
3.2.3. 三級封鎖協議
- 一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。
- 三級封鎖協議可防止丟失修改、讀髒數據和不可重複讀。
- 事務T1在讀A,B之前,先對A,B加S鎖
- 其他事務只能再對A,B加S鎖,而不能加X鎖,即其他事務只能讀A,B,而不能修改
- 當T2爲修改B而申請對B的X鎖時被拒絕只能等待T1釋放B上的鎖
- T1爲驗算再讀A,B,這時讀出的B仍是100,求和結果仍爲150,即可重複讀
- T1結束才釋放A,B上的S鎖。T2才獲得對B的X鎖
3.2.4 封鎖協議小結
三級協議的主要區別
- 什麼操作需要申請封鎖以及何時釋放鎖(即持鎖時間)
不同的封鎖協議使事務達到的一致性級別不同
- 封鎖協議級別越高,一致性程度越高
不同級別的封鎖協議和一致性保證
4 活鎖和死鎖
4.1 活鎖
- 事務T1封鎖了數據R
- 事務T2又請求封鎖R,於是T2等待。
- T3也請求封鎖R,當T1釋放了R上的封鎖之後系統首先批准了T3的請求,T2仍然等待。
- T4又請求封鎖R,當T3釋放了R上的封鎖之後系統又批准了T4的請求……
- T2有可能永遠等待,這就是活鎖的情形
避免活鎖:採用先來先服務的策略 - 當多個事務請求封鎖同一數據對象時
- 按請求封鎖的先後次序對這些事務排隊
- 該數據對象上的鎖一旦釋放,首先批准申請隊列中第一個事務獲得鎖
4.2 死鎖
- 事務T1封鎖了數據R1
- T2封鎖了數據R2
- T1又請求封鎖R2,因T2已封鎖了R2,於是T1等待T2釋放R2上的鎖
- 接着T2又申請封鎖R1,因T1已封鎖了R1,T2也只能等待T1釋放R1上的鎖
- 這樣T1在等待T2,而T2又在等待T1,T1和T2兩個事務永遠不能結束,形成死鎖
解決死鎖的方法:
4.2.1. 死鎖的預防
- 產生死鎖的原因是兩個或多個事務都已封鎖了一些數據對象,然後又都請求對已爲其他事務封鎖的數據對象加鎖,從而出現死等待。
- 預防死鎖的發生就是要破壞產生死鎖的條件
預防死鎖的方法
1. 一次封鎖法
要求每個事務必須一次將所有要使用的數據全部加鎖,否則就不能繼續執行
存在的問題
- 降低系統併發度
- 難於事先精確確定封鎖對象
- 數據庫中數據是不斷變化的,原來不要求封鎖的數據,在執行過程中可能會變成封鎖對象,所以很難事先精確地確定每個事務所要封鎖的數據對象。
- 解決方法:將事務在執行過程中可能要封鎖的數據對象全部加鎖,這就進一步降低了併發度。
2. 順序封鎖法
順序封鎖法是預先對數據對象規定一個封鎖順序,所有事務都按這個順序實行封鎖。
順序封鎖法存在的問題
- 維護成本
數據庫系統中封鎖的數據對象極多,並且隨數據的插入、刪除等操作而不斷地變化,要維護這樣的資源的封鎖順序非常困難,成本很高。 - 難以實現
事務的封鎖請求可以隨着事務的執行而動態地決定,很難事先確定每一個事務要封鎖哪些對象,因此也就很難按規定的順序去施加封鎖
3.結論 - 在操作系統中廣爲採用的預防死鎖的策略並不太適合數據庫的特點
- 數據庫管理系統在解決死鎖的問題上更普遍採用的是診斷並解除死鎖的方法
4.2.2. 死鎖的診斷與解除
1.超時法診斷
如果一個事務的等待時間超過了規定的時限,就認爲發生了死鎖
優點:實現簡單
缺點
- 有可能誤判死鎖
- 時限若設置得太長,死鎖發生後不能及時發現
2.等待圖法診斷
用事務等待圖動態反映所有事務的等待情況
- 事務等待圖是一個有向圖G=(T,U)
- T爲結點的集合,每個結點表示正運行的事務
- U爲邊的集合,每條邊表示事務等待的情況
- 若T1等待T2,則T1,T2之間劃一條有向邊,從T1指向T2
- 圖(a)中,事務T1等待T2,T2等待T1,產生了死鎖
- 圖(b)中,事務T1等待T2,T2等待T3,T3等待T4,T4又等待T1,產生了死鎖
- 圖(b)中,事務T3可能還等待T2,在大回路中又有小的迴路
併發控制子系統週期性地(比如每隔數秒)生成事務等待圖,檢測事務。如果發現圖中存在迴路,則表示系統中出現了死鎖。
3.解除死鎖
- 選擇一個處理死鎖代價最小的事務,將其撤消
- 釋放此事務持有的所有的鎖,使其它事務能繼續運行下去
5 併發調度的可串行性
- 數據庫管理系統對併發事務不同的調度可能會產生不同的結果
- 串行調度是正確的
- 執行結果等價於串行調度的調度也是正確的,稱爲可串行化調度
5.1可串行化調度
可串行化(Serializable)調度
- 多個事務的併發執行是正確的,當且僅當其結果與按某一次序串行地執行這些事務時的結果相同
可串行性(Serializability)
- 是併發事務正確調度的準則
- 一個給定的併發調度,當且僅當它是可串行化的,才認爲是正確調度
例:現在有兩個事務,分別包含下列操作:
事務T1:讀B;A=B+1;寫回A
事務T2:讀A;B=A+1;寫回B
現給出對這兩個事務不同的調度策略
- 假設A、B的初值均爲2。
- 按T1→T2次序執行結果爲A=3,B=4
- 串行調度策略,正確的調度
- 假設A、B的初值均爲2。
- T2→T1次序執行結果爲B=3,A=4
- 串行調度策略,正確的調度
- 執行結果與(a)、(b)的結果都不同
- 是錯誤的調度
- 執行結果與串行調度(a)的執行結果相同
- 是正確的調度
5.1衝突可串行化調度
- 一個比可串行化更嚴格的條件
- 商用系統中的調度器採用
衝突操作:是指不同的事務對同一數據的讀寫操作和寫寫操作:
Ri(x)與Wj(x) /事務Ti讀x,Tj寫x,其中i≠j/
Wi(x)與Wj(x) /事務Ti寫x,Tj寫x,其中i≠j/
其他操作是不衝突操作
不能交換(Swap)的動作:
-
同一事務的兩個操作
-
不同事務的衝突操作
-
一個調度Sc在保證衝突操作的次序不變的情況下,通過交換兩個事務不衝突操作的次序得到另一個調度Sc’,如果Sc’是串行的,稱調度Sc是衝突可串行化的調度
-
若一個調度是衝突可串行化,則一定是可串行化的調度
-
可用這種方法判斷一個調度是否是衝突可串行化的
衝突可串行化調度是可串行化調度的充分條件,不是必要條件。還有不滿足衝突可串行化條件的可串行化調度。
[例] 有3個事務
T1=W1(Y)W1(X),T2=W2(Y)W2(X),T3=W3(X)
調度L1=W1(Y)W1(X)W2(Y)W2(X) W3(X)是一個串行調度。
調度L2=W1(Y)W2(Y)W2(X)W1(X)W3(X)不滿足衝突可串行化。但是調度L2是可串行化的,因爲L2執行的結果與調度L1相同,Y的值都等於T2的值,X的值都等於T3的值
6 兩段鎖協議
數據庫管理系統普遍採用兩段鎖協議的方法實現併發調度的可串行性,從而保證調度的正確性
指所有事務必須分兩個階段對數據項加鎖和解鎖
- 在對任何數據進行讀、寫操作之前,事務首先要獲得對該數據的封鎖
- 在釋放一個封鎖之後,事務不再申請和獲得任何其他封鎖
“兩段”鎖的含義
- 事務分爲兩個階段
- 第一階段是獲得封鎖,也稱爲擴展階段
事務可以申請獲得任何數據項上的任何類型的鎖,但是不能釋放任何鎖 - 第二階段是釋放封鎖,也稱爲收縮階段
事務可以釋放任何數據項上的任何類型的鎖,但是不能再申請任何鎖
- 第一階段是獲得封鎖,也稱爲擴展階段
例
事務Ti遵守兩段鎖協議,其封鎖序列是 :
Slock A Slock B Xlock C Unlock B Unlock A Unlock C;
|← 擴展階段 →| |← 收縮階段 →|
事務Tj不遵守兩段鎖協議,其封鎖序列是:
Slock A Unlock A Slock B Xlock C Unlock C Unlock B;
左圖的調度是遵守兩段鎖協議的,因此一定是一個可行化調度。
如何驗證?
- 事務遵守兩段鎖協議是可串行化調度的充分條件,而不是必要條件。
- 若併發事務都遵守兩段鎖協議,則對這些事務的任何併發調度策略都是可串行化的
- 若併發事務的一個調度是可串行化的,不一定所有事務都符合兩段鎖協議
兩段鎖協議與防止死鎖的一次封鎖法
- 一次封鎖法要求每個事務必須一次將所有要使用的數據全部加鎖,否則就不能繼續執行,因此一次封鎖法遵守兩段鎖協議
- 但是兩段鎖協議並不要求事務必須一次將所有要使用的數據全部加鎖,因此遵守兩段鎖協議的事務可能發生死鎖
遵守兩段鎖協議的事務可能 發生死鎖
7 封鎖的粒度
封鎖對象的大小稱爲封鎖粒度(Granularity)
封鎖的對象:邏輯單元,物理單元
例:在關係數據庫中,封鎖對象:
- 邏輯單元: 屬性值、屬性值的集合、元組、關係、索引項、整個索引、整個數據庫等
- 物理單元:頁(數據頁或索引頁)、物理記錄等
封鎖粒度與系統的併發度和併發控制的開銷密切相關
- 封鎖的粒度越大,數據庫所能夠封鎖的數據單元就越少,併發度就越小,系統開銷也越小;
- 封鎖的粒度越小,併發度較高,但系統開銷也就越大
例
若封鎖粒度是數據頁,事務T1需要修改元組L1,則T1必須對包含L1的整個數據頁A加鎖。如果T1對A加鎖後事務T2要修改A中元組L2,則T2被迫等待,直到T1釋放A。
如果封鎖粒度是元組,則T1和T2可以同時對L1和L2加鎖,不需要互相等待,提高了系統的並行度。
又如,事務T需要讀取整個表,若封鎖粒度是元組,T必須對錶中的每一個元組加鎖,開銷極大
多粒度封鎖(Multiple Granularity Locking)
在一個系統中同時支持多種封鎖粒度供不同的事務選擇
選擇封鎖粒度
同時考慮封鎖開銷和併發度兩個因素, 適當選擇封鎖粒度
- 需要處理多個關係的大量元組的用戶事務:以數據庫爲封鎖單位
- 需要處理大量元組的用戶事務:以關係爲封鎖單元
- 只處理少量元組的用戶事務:以元組爲封鎖單位
7.1 多粒度封鎖
多粒度樹
以樹形結構來表示多級封鎖粒度
根結點是整個數據庫,表示最大的數據粒度
葉結點表示最小的數據粒度
三級粒度樹。根結點爲數據庫,數據庫的子結點爲關係,關係的子結點爲元組。
多粒度封鎖協議
- 允許多粒度樹中的每個結點被獨立地加鎖
- 對一個結點加鎖意味着這個結點的所有後裔結點也被加以同樣類型的鎖
- 在多粒度封鎖中一個數據對象可能以兩種方式封鎖:顯式封鎖和隱式封鎖
顯式封鎖和隱式封鎖
- 顯式封鎖: 直接加到數據對象上的封鎖
- 隱式封鎖:是該數據對象沒有獨立加鎖,是由於其上級結點加鎖而使該數據對象加上了鎖
- 顯式封鎖和隱式封鎖的效果是一樣的
系統檢查封鎖衝突時 - 要檢查顯式封鎖
- 還要檢查隱式封鎖
例如事務T要對關係R1加X鎖
系統必須搜索其上級結點數據庫、關係R1
還要搜索R1的下級結點,即R1中的每一個元組
如果其中某一個數據對象已經加了不相容鎖,則T必須等待
對某個數據對象加鎖,系統要檢查
- 該數據對象
有無顯式封鎖與之衝突 - 所有上級結點
檢查本事務的顯式封鎖是否與該數據對象上的隱式封鎖衝突:(由上級結點已加的封鎖造成的) - 所有下級結點
看上面的顯式封鎖是否與本事務的隱式封鎖(將加到下級結點的封鎖)衝突
7.2 意向鎖
引進意向鎖(intention lock)目的
- 提高對某個數據對象加鎖時系統的檢查效率
如果對一個結點加意向鎖,則說明該結點的下層結點正在被加鎖
對任一結點加基本鎖,必須先對它的上層結點加意向鎖
例如,對任一元組加鎖時,必須先對它所在的數據庫和關係加意向鎖
常用意向鎖
-
意向共享鎖(Intent Share Lock,簡稱IS鎖)
如果對一個數據對象加IS鎖,表示它的後裔結點擬(意向)加S鎖。
例如:事務T1要對R1中某個元組加S鎖,則要首先對關係R1和數據庫加IS鎖 -
意向排它鎖(Intent Exclusive Lock,簡稱IX鎖)
如果對一個數據對象加IX鎖,表示它的後裔結點擬(意向)加X鎖。
例如:事務T1要對R1中某個元組加X鎖,則要首先對關
系R1和數據庫加IX鎖 -
共享意向排它鎖(Share Intent Exclusive Lock,簡稱SIX鎖)
如果對一個數據對象加SIX鎖,表示對它加S鎖,再加IX鎖,即SIX = S + IX。
例:對某個表加SIX鎖,則表示該事務要讀整個表(所以要對該表加S鎖),同時會更新個別元組(所以要對該表加IX鎖)。
鎖的強度
- 鎖的強度是指它對其他鎖的排斥程度
- 一個事務在申請封鎖時以強鎖代替弱鎖是安全的,反之則不然
具有意向鎖的多粒度封鎖方法 - 申請封鎖時應該按自上而下的次序進行
- 釋放封鎖時則應該按自下而上的次序進行
例如:事務T1要對關係R1加S鎖
- 要首先對數據庫加IS鎖
- 檢查數據庫和R1是否已加了不相容的鎖(X或IX)
- 不再需要搜索和檢查R1中的元組是否加了不相容的鎖(X鎖)
具有意向鎖的多粒度封鎖方法
- 提高了系統的併發度
- 減少了加鎖和解鎖的開銷
- 在實際的數據庫管理系統產品中得到廣泛應用
8 其他併發控制機制(略)
9 小結
數據庫的併發控制以事務爲單位
數據庫的併發控制通常使用封鎖機制
- 基本封鎖
- 多粒度封鎖
活鎖和死鎖
併發事務調度的正確性
- 可串行性
- 併發操作的正確性則通常由兩段鎖協議來保證。
- 兩段鎖協議是可串行化調度的充分條件,但不是必要條件
- 衝突可串行性
其他併發控制機制
- 時間戳方法
- 樂觀控制法
- 多版本併發控制