事務基本概念
事務
是一系列的數據庫操作,是數據庫應用程序的基本邏輯單元所謂事務是用戶自定義的一個數據庫操作序列,這些操作要么全做,要么不做,是一個不可分割的工作單位。
例如:在關系型數據庫中,一個事務可以是一條sql,一組sql或整個程序
事務和程序的區別:一般來說,一個程序中包含很多事務
事務的定義
事務的開始與結束可以由用戶顯式控制,若用戶沒有顯式控制,則有數據庫管理系統默認划分事務
1、begin transaction;
事務的開始,以commit或rollback結束。
2、commit;
即提交事務的所有操作:將事務中所有對數據庫的更新寫回到磁盤上的物理數據庫中,事務正常結束。
3、rollback;
回滾,即當事務運行過程中發生了某種故障,不在繼續執行時,系統將事務中對數據庫所有已完成的操作全部撤銷,回滾到事務開始時的狀態。
事務的特點
- 原子性
- 一致性
- 隔離性
- 持續性【永久性】
事務處理技術
數據庫恢復
數據恢復的常用技術:數據轉儲、登記日志文件
日志文件:
用來記錄事務對數據庫的更新操作的文件
作用:在數據庫恢復中起到重要作用,並協助后備副本進行介質故障恢復
主要包含:事務標識、操作類型、操作對象、更新前數據的舊值、更新后數據的新值
數據故障
1、事務內部故障
是非預期的,不能由應用程序處理
2、系統故障【軟故障】
指造成系統停止運轉的任何事件,使得系統要重啟
3、介質故障【硬故障】
4、計算機病毒
2、采用什么機制來保證數據庫並發操作的正確性?
並發控制
單處理機系統中,事務的並行執行實際上是這些並行事務的並行操作輪流交叉運行並發操作帶來的數據不一致有三種情況:
1、丟失修改
寫-寫
兩個事務T1和T2讀入同一數據並修改,T2提交的結果破壞了T1提交的結果,導致T1的修改被丟失。
解決辦法:
一種辦法是是鎖,即基於鎖的並發控制,比如2PL,這種方式開銷比較高,而且無法避免死鎖。
樂觀並發控制(OCC)是一種用來解決寫-寫沖突的無鎖並發控制,認為事務間爭用沒有那么多,所以先進行修改,在提交事務前,檢查一下事務開始后,有沒有新提交改變,如果沒有就提交,如果有就放棄並重試。樂觀並發控制類似自選鎖。樂觀並發控制適用於低數據爭用,寫沖突比較少的環境。
多版本並發控制可以結合基於鎖的並發控制來解決寫-寫沖突,即MVCC+2PL,也可以結合樂觀並發控制來解決寫-寫沖突。
2、不可重復讀
讀-寫
事務T1讀取數據后,事務T2執行更新操作,使T1無法再現前一次讀取結果。
3、讀“ 臟 ”數據 【污讀】
讀-寫
事務 T1修改某一數據,並將其寫回磁盤,事務T2讀取同一數據后, T1由於某種原因被撤消,這時 T1已修改過的數據恢復原值,
T2讀到的數據就與數據庫中的數據不一致,則T2讀到的數據就為"臟"數據,即不正確的數據。(讀取到未提交數據)
解決辦法:
多版本並發控制(MVCC)是一種用來解決讀-寫沖突的無鎖並發控制,也就是系統為每個事務分配單向增長的時間戳,為每個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫的快照。 這樣在讀操作不用阻塞寫操作,寫操作不用阻塞讀操作的同時,避免了臟讀和不可重復讀。
並發控制的解決辦法
並發控制的主要技術有封鎖(locking)、時間戳(timestamp)、樂觀控制法(optimistic sheduler)和多版本並發控制(multi-version concurrency control,MVCC)等,各個技術之間是存在交叉配合使用的。商用的DBMS一般都采用封鎖方法。
悲觀並發控制:假定會發生並發沖突,屏蔽一切可能違反數據完整性的操作。
樂觀並發控制:假設不會發生並發沖突,只在提交操作時檢查是否違反數據完整性。封鎖
事務T在對某個數據對象(例如表、記錄等)操作之前,先向系統發出請求,對其加鎖。加鎖后事務T就對該數據對象有了一定的控制權,在事務T釋放它的鎖之前,其它的事務不能更新此數據對象,屬於一種悲觀控制法。
封鎖的基本類型
基本的封鎖類型有兩種:排他鎖(X鎖)和共享鎖(S鎖)。
(1)排它鎖又稱寫鎖X。若事務T對數據對象A加上X鎖,只有事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。這保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。
(2)共享鎖又稱讀鎖S。若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。
封鎖協議
一級封鎖協議:對應事務隔離級別中的讀未提交(Read uncommited)
事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放。事務結束包括正常結束(COMMIT)和非正常結束(ROLLBACK)。
一級封鎖協議可防止丟失修改,並保證事務T是可恢復的,因為防止其他事務進行同時修改。
在一級封鎖協議中,如果僅僅是讀數據不對其進行修改,是不需要加鎖的。所以它不能保證可重復讀和不 讀"臟"數據。
非正常結束時,X鎖就自動釋放了!
二級封鎖協議:對應事務隔離級別中的讀已提交(Read Committed)
一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完后即可釋放S鎖。二級封鎖協議防止了丟失修改和讀"臟"數據。
遵從二級封鎖協議時發生的“不可重復讀”的過程
三級封鎖協議:對應事務隔離級別中的可重復讀(Repeatable Read)
一級封鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,直到事務結束才釋放。三級封鎖協議除防止了丟失修改和不讀'臟'數據外,還進一步防止了不可重復讀。
封鎖中的死鎖與活鎖
活鎖
存在現象:如果事務T1封鎖了數據R,事務T2又請求封鎖數據R,於是T2等待。事務T3也請求封鎖R,當事務T1釋放了數據R上的封鎖之后系統首先批准了事務T3的封鎖請求,T2仍然等待。然后T4又申請封鎖R,當T3釋放了R的封鎖之后系統又批准了T4的封鎖請求。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) 死鎖的預防:
①一次封鎖法
一次封鎖法要求事務必須一次將所有要使用的數據全部加鎖,否則不能繼續執行。例如上圖中的事務T1將數據R1和R2一次加鎖,T1就能執行下去,而T2等待。T1執行完成之后釋放R1,R2上的鎖,T2繼續執行。這樣就不會產生死鎖。
一次封鎖法雖然能防止死鎖的發生,但是缺點卻很明顯。一次性將以后要用到的數據加鎖,勢必擴大了封鎖的范圍 ,從而降低了系統的並發度。
②順序封鎖法
順序封鎖法是預先對數據對象規定一個封鎖順序,所有的事務都按照這個順序實行封鎖。
順序封鎖法雖然可以有效避免死鎖,但是問題也很明顯。第一,數據庫系統封鎖的數據對象極多,並且隨着數據的插入、刪除等操作不斷變化,要維護這樣的資源的封鎖順序非常困難,成本很高。第二,事務的封鎖請求可以隨着事務的執行動態的確定,因此很難按照規定的順序實行封鎖。
可見,預防死鎖的產生並不是很適合數據庫的特點,所以在解決死鎖的問題上普遍采用的是診斷並且解除死鎖。
2) 死鎖的診斷與解除:
①超時法
如果一個事務的等待時間超過了默認的時間,就認為是產生了死鎖。
②等待圖法
一旦檢測到系統中存在死鎖就要設法解除。通常的解決方法是選擇一個處理死鎖代價最小的事務,將其撤銷,釋放此事務持有的所有的鎖,恢復其所執行的數據修改操作,使得其他事務得以運行下去。
兩段鎖協議2PL
所謂的二段鎖協議是指所有事務必須分兩個階段對數據進行加鎖和解鎖操作。
在對任何數據進行讀、寫操作之前,首先要申請並獲得該數據的封鎖。
在釋放一個封鎖之后,事務不在申請和獲得其他封鎖。
也就是說事務分為兩個階段。第一個階段是獲得封鎖,也稱為擴展階段。在這個階段,事務可以申請獲得任何數據項任何類型的鎖,但是不能釋放任何鎖。第二階段是釋放封鎖,也稱為收縮階段。在這個階段,事務可以釋放任何數據項上任何類型的封鎖,但是不能再申請任何鎖。
事務遵守兩段鎖協議是可串行化調度的充分條件,而不是必要條件。也就是說遵守兩段鎖協議一定是可串行化調度的,而可串行化調度的不一定是遵守兩段鎖協議的。
兩段鎖協議和一次封鎖法的異同
一次封鎖法要求事務必須將要使用的數據全部加鎖,否則不能繼續執行。因此一次封鎖法遵守兩段鎖協議。
但是兩段鎖協議並不要求事務將要使用的數據一次全部加鎖,因此兩段鎖協議可能發生死鎖。
時間戳
給每個事務分配一個全局惟一的時間戳。時間截的值產生了一個精確的順序,事務按照該順序提交。時間戳必須有兩個特性:惟一性和單調性,惟一性保證不存在相等的時間戳值,單調性保證時間戳的值是一直增長的。
同一事務中所有的數據庫操作(讀和寫)都必須有相同的時間戳。DBMS按照時間戳順序執行沖突的事務,因此保證了事務的可串行化。如果兩個事務沖突,通常終止其中一個,將其回滾並重新調度,賦予新的時間戳。
用時間戳實現並發控制,需要為數據庫中每個值附加兩個字段
讀時間戳:用於保存所有訪問該記錄的事務中的最大時間戳(最后讀取時間)
寫時間戳:用於保存將記錄改到當前值的事務的時間戳(最后修改時間)
因此時間戳增加了內存需求和數據庫的處理開銷,因為有可能導致許多事務被終止,重新調度和重新賦予時間戳,時間戳方法一般需要大量的系統資源.
這樣的事務在並行執行時,用的是樂觀控制,先任由事務對數據進行修改,在寫回去的時候在判斷記錄的時間戳有沒有修改,如果沒有被修改,就寫入,否則,就生成一個新的時間戳並再次嘗試更新數據。
樂觀控制法
樂觀方法基於這樣的假設,數據庫操作的大部分都不會發生沖突,樂觀方法不要求鎖定,作為替換,事務不受限制地被執行,直到它被提交,便用樂觀方法,每個事務經過兩個或者三個階段,它們是讀、確認、寫。
(1)讀階段,事務讀取數據庫,執行需要的計算,並對一個私有的數據庫值的副本進行更新,事務的所有更新操作都記錄在一個臨時更新文件中,該文件將不 ,會被剩下的其他事務訪問.
(2)確認階段,對事務進行確認以保證所做的修改不會影響數據庫的完整性和一致性,如果確認檢查是肯定的,事務進入寫階段;如果確認檢查是否定的,則事務回滾,重新啟動,所做的修改被拋棄
(3)寫階段,所做的修改被永久地寫入到數據庫中,樂觀方法對於大多數只有較少更新事務的查詢數據庫系統來說是可以接受的,
多版本並發控制
MVCC (Multiversion Concurrency Control),即多版本並發控制技術,是一種並發控制的方法,一般在數據庫管理系統中,實現對數據庫的並發訪問。在MVCC中,每個事務操作的是數據的一個快照,寫操作造成的變化在寫操作完成之前(或者數據庫事務提交之前)對於其他的事務來說是不可見的。
當一個 MVCC 數據庫需要更一個一條數據記錄的時候,它不會直接用新數據覆蓋舊數據,而是將舊數據標記為過時(obsolete)並在別處增加新版本的數據。這樣就會有存儲多個版本的數據,但是只有一個是最新的。這種方式允許事務讀取在他讀之前已經存在的數據,即使這些在讀的過程中半路被別人修改、刪除了,也對先前正在讀的用戶沒有影響。這種多版本的方式避免了填充刪除操作在內存和磁盤存儲結構造成的空洞的開銷,但是需要系統周期性整理(sweep through)以真實刪除老的、過時的數據。
MVCC 並發控制下的讀事務一般使用
時間戳
或者事務ID
去標記當前讀的數據庫的狀態(版本),讀取這個版本的數據。讀、寫事務相互隔離,不需要加鎖。讀寫並存的時候,寫操作會根據目前數據庫的狀態,創建一個新版本,並發的讀則依舊訪問舊版本的數據。一句話講,MVCC就是用 同一份數據臨時保留多版本的方式的方式,實現並發控制。 這里留意到 MVCC 關鍵的兩個點: 在讀寫並發的過程中如何實現多版本; 在讀寫並發之后,如何實現舊版本的刪除(畢竟很多時候只需要一份最新版的數據就夠了)
轉載