數據庫事務(二)
數據併發的問題
一個數據庫可能擁有多個訪問客戶端,這些客戶端都可以併發方式訪問數據庫。數據庫中的相同數據可能同時被多個事務訪問,如果沒有采取必要的隔離措施,就會導致各種併發問題,破壞數據的完整性。這些問題可以歸結爲5類,包括3類數據讀問題(髒讀、幻象讀和不可重複讀)以及2類數據更新問題(第一類丟失更新和第二類丟失更新)。下面,我們分別通過實例講解引發問題的場景。
髒讀(dirty read)
在講解髒讀前,我們先講一個笑話:一個有結巴的人在飲料店櫃檯前轉悠,老闆很熱情地迎上來:“喝一瓶?”,結巴連忙說:“我…喝…喝…”,老闆麻利地打開易拉罐遞給結巴,結巴終於憋出了他的那句話:“我…喝…喝…喝不起啊!”。在這個笑話中,飲料店老闆就對結巴進行了髒讀。
A事務讀取B事務尚未提交的更改數據,並在這個數據的基礎上操作。如果恰巧B事務回滾,那麼A事務讀到的數據根本是不被承認的。來看取款事務和轉賬事務併發時引發的髒讀場景:
時間
|
轉賬事務A
|
取款事務B
|
T1
|
|
開始事務
|
T2
|
開始事務
|
|
T3
|
|
查詢賬戶餘額爲1000元
|
T4
|
|
取出500元把餘額改爲500元
|
T5
|
查詢賬戶餘額爲500元(髒讀)
|
|
T6
|
|
撤銷事務餘額恢復爲1000元
|
T7
|
匯入100元把餘額改爲600元
|
|
T8
|
提交事務
|
|
在這個場景中,B希望取款500元而後又撤銷了動作,而A往相同的賬戶中轉賬100元,就因爲A事務讀取了B事務尚未提交的數據,因而造成賬戶白白丟失了500元。
不可重複讀(unrepeatable read)
不可重複讀是指A事務讀取了B事務已經提交的更改數據。假設A在取款事務的過程中,B往該賬戶轉賬100元,A兩次讀取賬戶的餘額發生不一致:
時間
|
取款事務A
|
轉賬事務B
|
T1
|
|
開始事務
|
T2
|
開始事務
|
|
T3
|
|
查詢賬戶餘額爲1000元
|
T4
|
查詢賬戶餘額爲1000元
|
|
T5
|
|
取出100元把餘額改爲900元
|
T6
|
|
提交事務
|
T7
|
查詢賬戶餘額爲900元(和T4讀取的不一致)
|
|
在同一事務中,T4時間點和T7時間點讀取賬戶存款餘額不一樣。
幻象讀(phantom read)
A事務讀取B事務提交的新增數據,這時A事務將出現幻象讀的問題。幻象讀一般發生在計算統計數據的事務中,舉一個例子,假設銀行系統在同一個事務中,兩次統計存款賬戶的總金額,在兩次統計過程中,剛好新增了一個存款賬戶,並存入100元,這時,兩次統計的總金額將不一致:
時間
|
統計金額事務A
|
轉賬事務B
|
T1
|
|
開始事務
|
T2
|
開始事務
|
|
T3
|
統計總存款數爲10000元
|
|
T4
|
|
新增一個存款賬戶,存款爲100元
|
T5
|
|
提交事務
|
T6
|
再次統計總存款數爲10100元(幻象讀)
|
|
如果新增數據剛好滿足事務的查詢條件,這個新數據就進入了事務的視野,因而產生了兩個統計不一致的情況。
幻象讀和不可重複讀是兩個容易混淆的概念,前者是指讀到了其它已經提交事務的新增數據,而後者是指讀到了已經提交事務的更改數據(更改或刪除),爲了避免這兩種情況,採取的對策是不同的,防止讀取到更改數據,只需要對操作的數據添加行級鎖,阻止操作中的數據發生變化,而防止讀取到新增數據,則往往需要添加表級鎖——將整個表鎖定,防止新增數據。
第一類丟失更新
A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。這種錯誤可能造成很嚴重的問題,通過下面的賬戶取款轉賬就可以看出來:
時間
|
取款事務A
|
轉賬事務B
|
T1
|
開始事務
|
|
T2
|
|
開始事務
|
T3
|
查詢賬戶餘額爲1000元
|
|
T4
|
|
查詢賬戶餘額爲1000元
|
T5
|
|
匯入100元把餘額改爲1100元
|
T6
|
|
提交事務
|
T7
|
取出100元把餘額改爲900元
|
|
T8
|
撤銷事務
|
|
T9
|
餘額恢復爲1000元(丟失更新)
|
|
A事務在撤銷時,“不小心”將B事務已經轉入賬戶的金額給抹去了。
第二類丟失更新
A事務覆蓋B事務已經提交的數據,造成B事務所做操作丟失:
時間
|
轉賬事務A
|
取款事務B
|
T1
|
|
開始事務
|
T2
|
開始事務
|
|
T3
|
|
查詢賬戶餘額爲1000元
|
T4
|
查詢賬戶餘額爲1000元
|
|
T5
|
|
取出100元把餘額改爲900元
|
T6
|
|
提交事務
|
T7
|
匯入100元
|
|
T8
|
提交事務
|
|
T9
|
把餘額改爲1100元(丟失更新)
|
|
上面的例子裏由於支票轉賬事務覆蓋了取款事務對存款餘額所做的更新,導致銀行最後損失了100元,相反如果轉賬事務先提交,那麼用戶賬戶將損失100元。