事物和並發性
在學習事物和並發性之前首先來理解兩個概念:
1、什麼事事物?
事物是SQL Server中的基本工作單元。通常它由幾個讀取和更新資料庫的SQL命令組成,但是這些操作都不被看為最終的,直到發出一個COMMIT命令為止。
2、什麼是並發性?
並發性可以定義為多個進程在相同時間訪問或者更改共用資料的能力。既然是能力,那麼一個系統的並發性就會有強弱之分。既然如此,我們該怎樣判斷一個系統並發行的強弱呢?
一般情況而言,一個系統在互不干擾的情況下可以啟用的並發使用者的進程數越多,該系統的並發性就越強。
可能影響並發性的一些原因分析:
當正在更改資料的進程阻止其他進程讀取該資料時,或者當讀取資料的進程阻止其他進程更改該資料時,並發行會減弱。另外,當多個進程試圖同時更改相同資料時,且無法在不犧牲資料的一致性的前提下都能成功時,並發性也會受到影響。對於並發性的理解我們和容易聯想到鐵道部的訂票網站。由於處理並發效能力不夠,導致訂票高峰出現奔潰現象,對網路訂票造成不良影響。由此可見,一個大型網站的資料庫系統提高處理並發性的能力是在必要。
處理並發性的方法:
SQLServer 2008提供兩種方法:樂觀和悲觀兩個模型。我們可以通過一下命令來指定:
SETTRANSACTION ISOLATION LEVEL(事物的隔離等級)來指定。
兩者的區別:
在兩種模型中,兩個進程試圖在相同時間修改相同資料時,可能會出現衝突。那麼這兩個模型之間的區別在於衝突是在出現前被避免還是在出現後採取某種方式進行處理。
封閉式並行存取模型:
對於封閉式並行存取SQL Server預設的行為是擷取鎖來阻塞對另一個進程正在使用的資料的訪問。封閉式並行存取假設系統中有足夠的資料修改操作,因而給定的任何一個讀寫操作都可能受到另外一個使用者的資料修改操作的影響。封閉式並行存取通過獲得正在被讀取資料上的鎖,使其他進程無法修改該資料而避免衝突。換言之,在悲觀模型下,讀取者阻塞寫入者,寫入者也阻塞讀取者。
開放式並行存取模型:
開放式並行存取假設系統中有足夠少的資料修改操作,因而任何單個事物都不太可能另一個事物正在修改的資料。開放式並行存取的預設行為是使用資料列版本設定來允許資料讀取者看到修改之前的資料狀態。資料行教老的版本被儲存,所以讀取資料的進程可以看到進程開始讀取時的資料,不會受到對該資料正在做出任何更改的進程的影響。換言之,讀取者不阻塞寫入者,寫入者也不阻塞讀取者,但是,寫入者可以而且會阻塞寫入者,這也是導致衝突的原因所在。這時SQL Server在衝突出現時產生一個錯誤資訊,但是是由應用程式來負責影響該錯誤。
交易處理:
ACID屬性
原子性:原子性保證每個事物被作為整體單元被處理或者不被處理,要麼全部處理,要麼全部不處理:
例如:
以下事物類比銀行轉帳
Begintrabsaction tran1
Updatetb
setaccount=account+100 where accountid=’a’
updatettb
setaccount=account-100 where accounted=’b’
Committransaction tran1
以上簡單的事物tran1中的兩條語句要麼都插入成功,要麼都失敗,不存在一條成功一條失敗的現象。
換句話說,原子性保證了事物內部的所有語句被看作為一個原子,而原子是不可被分割的。
一致性:一致性確保事物不會允許系統達到不正確的邏輯狀態。即使出現系統故障,也遵循所有的約束和規則。
例如上面的模仿銀行轉賬的事物,事物的一致性確保了在a賬戶增加100遠的同時b賬戶減少100元。避免了當a賬戶增加100後,系統出現故障而造成的b賬戶沒有減少相應的資金。這確保了資料的一致性。
隔離性:隔離性將並發事物與其他未完成的事務的更新隔離開來。在上面的例子中,另一個事物無法看到這個正在執行的事物中所進行的工作。
持久性:在事物提交後,SQL Server的持久性屬性確保事務的效果持久存在,即使出現系統故障亦是如此。
事物的依賴性
丟失更新:當兩個進程讀取相同資料,並且都操作資料,更改他的值,還試圖將未經處理資料更新到新值,會出現資料丟失。例如:
A,B兩個店員都接收到運來的組件。他們檢查當前庫存,並且看到存貨當中還有25個組件。店員A收到的貨是50個組件,所以他將50+25寫入當前庫存。店員B收到的是25個組件,所以他將20+25寫入到資料庫,覆蓋了A添加的50個,這樣就出現了資料更新丟失
髒讀:髒讀出現在進程讀取未提交資料時。例如:A店員將原來的25個組件更新為75,在他提交之前,一個銷售人員看到當前庫存是75,並答應第二天給客戶發60個組件。如果店員A發現這批零件中有缺陷,並且返回給供應商,並將庫存更新為25,實際上就是銷售人員進行了一次髒讀,並基於未提交資料採取行動。預設情況下髒讀是不允許的。
注意:更新資料的進程無法控制另一個進程是否可以在第一個進程提交之前讀取他的資料。而是由讀取資料的進程來決定它是否要讀取不能保證已經提交的資料。
不可重複度:如果進程同一事物兩次獨立的讀操作中讀取相同的資料取得到不同的值,那麼這樣的讀是不可重複的。
幻讀:
事物的隔離等級:
未提交讀:
已提交讀:
可重複度:
快照:
可序列化:
每種隔離等級中允許的行為,如下表:
隔離等級 髒讀 不可重複度 幻讀 並發控制
未提交讀 Y Y Y 悲觀
已提交讀(鎖定) N Y Y 悲觀
已提交讀(快照) N Y Y 樂觀
可重複度 N N Y 悲觀
快照 N N N 樂觀
可序列化 N N N 悲觀
註:以上表格中的Y代表可以,N代表不可以