對並發操作進行正確調度
保證事務的隔離性
保證數據庫的一致性
多用戶數據庫系統的存在
允許多個用戶同時使用的數據庫系統
飛機定票數據庫系統
銀行數據庫系統
特點:在同一時刻並發運行的事務數可達數百個
不同的多事務執行方式
(1)事務串行執行
每個時刻只有一個事務運行,其他事務必須等到這個事務結束以後方能運行
不能充分利用系統資源,發揮數據庫共享資源的特點
(2)交叉並發方式(Interleaved Concurrency)
在單處理機系統中,事務的並行執行是這些並行事務的並行操作輪流交叉運行
單處理機系統中的並行事務並沒有真正地並行運行,但能夠減少處理機的空閒時間,提高系統的效率
(3)同時並發方式(simultaneous concurrency)
多處理機系統中,每個處理機可以運行一個事務,多個處理機可以同時運行多個事務,實現多個事務真正的並行運行
事務並發執行帶來的問題
會產生多個事務同時存取同一數據的情況
可能會存取不正確的數據,破壞事務的一致性和數據庫的一致性
並發操作帶來數據的不一致性實例
[例1]飛機訂票系統中的一個活動序列
① 甲售票點(甲事務)讀出某航班的機票余額A,設A=16;
② 乙售票點(乙事務)讀出同一航班的機票余額A,也為16;
③ 甲售票點賣出一張機票,修改余額A←A-1,所以A為15,把A寫回數據庫;
④ 乙售票點也賣出一張機票,修改余額A←A-1,所以A為15,把A寫回數據庫
結果明明賣出兩張機票,數據庫中機票余額只減少1
這種情況稱為數據庫的不一致性,是由並發操作引起的。
在並發操作情況下,對甲、乙兩個事務的操作序列的調度是隨機的。
若按上面的調度序列執行,甲事務的修改就被丟失。
原因:第4步中乙事務修改A並寫回後覆蓋了甲事務的修改
並發操作帶來的數據不一致性(不正確性)
丟失修改(Lost Update)
不可重復讀(Non-repeatable Read)
讀“髒”數據(Dirty Read)
記號
R(x):讀數據x
W(x):寫數據x
兩個事務T1和T2讀入同一數據並修改,T2的提交結果破壞了T1提交的結果,導致T1的修改被丟失。
上面飛機訂票例子就屬此類
不可重復讀是指事務T1讀取數據後,事務T2
執行更新操作,使T1無法再現前一次讀取結果。
不可重復讀包括三種情況:
(1)事務T1讀取某一數據後,事務T2對其做了修改,當事務T1再次讀該數據時,得到與前一次不同的值
(2)事務T1按一定條件從數據庫中讀取了某些數據記錄後,事務T2刪除了其中部分記錄,當T1再次按相同條件讀取數據時,發現某些記錄消失了
(3)事務T1按一定條件從數據庫中讀取某些數據記錄後,事務T2插入了一些記錄,當T1再次按相同條件讀取數據時,發現多了一些記錄。
後兩種不可重復讀有時也稱為幻影現象(Phantom Row)
讀“髒”數據是指:
事務T1修改某一數據,並將其寫回磁盤
事務T2讀取同一數據後,T1由於某種原因被撤銷
這時T1已修改過的數據恢復原值,T2讀到的數據就與數據庫中的數據不一致
T2讀到的數據就為“髒”數據,即不正確的數據
數據不一致性:由於並發操作破壞了事務的隔離性
並發控制就是要用正確的方式調度並發操作,使一個用戶事務的執行不受其他事務的干擾,從而避免造成數據的不一致性
並發控制的主要技術
封鎖(Locking)
時間戳(Timestamp)
樂觀控制法
商用的DBMS一般都采用封鎖方法
並發控制的主要技術
封鎖(Locking)
時間戳(Timestamp)
樂觀控制法
商用的DBMS一般都采用封鎖方法
一個事務對某個數據對象加鎖後究竟擁有什麼樣的控制由封鎖的類型決定。
基本封鎖類型
排它鎖(eXclusive Locks,簡記為X鎖)
共享鎖(Share Locks,簡記為S鎖)
排它鎖又稱為寫鎖
若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖
保證其他事務在T釋放A上的鎖之前不能再讀取和修改A
共享鎖又稱為讀鎖
若事務T對數據對象A加上S鎖,則其它事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖
保證其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改
在鎖的相容矩陣中:
最左邊一列表示事務T1已經獲得的數據對象上的鎖的類型,其中橫線表示沒有加鎖。
最上面一行表示另一事務T2對同一數據對象發出的封鎖請求。
T2的封鎖請求能否被滿足用矩陣中的Y和N表示
Y表示事務T2的封鎖要求與T1已持有的鎖相容,封鎖請求可以滿足
N表示T2的封鎖請求與T1已持有的鎖沖突,T2的請求被拒絕
封鎖技術可以有效地解決並行操作的一致性問題,但也帶來一些新的問題
死鎖
事務T1封鎖了數據R1
T2封鎖了數據R2
T1又請求封鎖R2,因T2已封鎖了R2,於是T1等待T2釋放R2上的鎖
接著T2又申請封鎖R1,因T1已封鎖了R1,T2也只能等待T1釋放R1上的鎖
這樣T1在等待T2,而T2又在等待T1,T1和T2兩個事務永遠不能結束,形成死鎖
兩類方法
1. 預防死鎖
2. 死鎖的診斷與解除
活鎖
事務T1封鎖了數據R
事務T2又請求封鎖R,於是T2等待。
T3也請求封鎖R,當T1釋放了R上的封鎖之後系統首先批准了T3的請求,T2仍然等待。
T4又請求封鎖R,當T3釋放了R上的封鎖之後系統又批准了T4的請求……
T2有可能永遠等待,這就是活鎖的情形
避免活鎖:采用先來先服務的策略
當多個事務請求封鎖同一數據對象時
按請求封鎖的先後次序對這些事務排隊
該數據對象上的鎖一旦釋放,首先批准申請隊列中第一個事務獲得鎖
產生死鎖的原因是兩個或多個事務都已封鎖了一些數據對象,然後又都請求對已為其他事務封鎖的數據對象加鎖,從而出現死等待。
預防死鎖的發生就是要破壞產生死鎖的條件
預防死鎖的方法
一次封鎖法
順序封鎖法
要求每個事務必須一次將所有要使用的數據全部加鎖,否則就不能繼續執行
存在的問題
降低系統並發度
難於事先精確確定封鎖對象
順序封鎖法是預先對數據對象規定一個封鎖順序,按順序編號,所有事務都按這個編號順序申請封鎖。
順序封鎖法存在的問題
維護成本
數據庫系統中封鎖的數據對象極多,並且在不斷地變化。
難以實現:很難事先確定每一個事務要封鎖哪些對象
結論
在操作系統中廣為采用的預防死鎖的策略並不很適合數據庫的特點
DBMS在解決死鎖的問題上更普遍采用的是診斷並解除死鎖的方法
死鎖的診斷
超時法
如果一個事務的等待時間超過了規定的時限,就認為發生了死鎖
優點:實現簡單
缺點
有可能誤判死鎖
時限若設置得太長,死鎖發生後不能及時發現
事務等待圖法
用事務等待圖動態反映所有事務的等待情況
事務等待圖是一個有向圖G=(T,U)
T為結點的集合,每個結點表示正運行的事務
U為邊的集合,每條邊表示事務等待的情況
若T1等待T2,則T1,T2之間劃一條有向邊,從T1指向T2
並發控制子系統周期性地(比如每隔數秒)生成事務等待圖,檢測事務。如果發現圖中存在回路,則表示系統中出現了死鎖。