乙個資料庫可能擁有多個訪問客戶端,這些客戶端都可以併發方式訪問資料庫。資料庫中的相同資料可能同時被多個事務訪問,如果沒有採取必要的隔離措施,就會導致各種併發問題,破壞資料的完整性。這些問題可以歸結為
5類,包括
3類資料讀問題(髒讀、幻象讀和不可重複讀)以及
2類資料更新問題(第一類丟失更新和第二類丟失更新)。
髒讀(dirty read)
事務讀取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元(幻象讀)
如果新增資料剛好滿足事務的查詢條件,這個新資料就進入了事務的視野,因而產生了兩個統計不一致的情況。
幻象讀和不可重複讀是兩個容易混淆的概念,前者是指讀到了其它已經提交事務的新增資料,而後者是指讀到了已經提交事務的更改資料(更改或刪除),為了避免這兩種情況,採取的對策是不同的,防止讀取到更改資料,只需要對操作的資料新增行級鎖,阻止操作中的資料發生變化,而防止讀取到新增資料,則往往需要新增表級鎖——將整個表鎖定,防止新增資料(oracle使用多版本資料的方式實現)。
第一類丟失更新
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元。
資料庫鎖機制
資料併發會引發很多問題,在一些場合下有些問題是允許的,但在另外一些場合下可能卻是致命的。資料庫通過鎖的機制解決併發訪問的問題,雖然不同的資料庫在實現細節上存在差別,但原理基本上是一樣的。
按鎖定的物件的不同,一般可以分為表鎖定和行鎖定,前者對整個表進行鎖定,而後者對錶中特定行進行鎖定。從併發事務鎖定的關係上看,可以分為共享鎖定和獨佔鎖定。共享鎖定會防止獨佔鎖定,但允許其它的共享鎖定。而獨佔鎖定既防止其它的獨佔鎖定,也防止其它的共享鎖定。為了更改資料,資料庫必須在進行更改的行上施加行獨佔鎖定,insert、update、delete和select for update語句都會隱式採用必要的行鎖定。下面我們介紹一下oracle資料庫常用的5種鎖定:
行共享鎖定:一般通過select for update語句隱式獲得行共享鎖定,在oracle中你也可以通過lock table in row share mode語句顯式獲得行共享鎖定。行共享鎖定並不防止對資料行進行更改的操作,但是可以防止其它會話獲取獨占性資料表鎖定。允許進行多個併發的行共享和行獨占性鎖定,還允許進行資料表的共享或者採用共享行獨佔鎖定;
行獨佔鎖定:通過一條insert、update或delete語句隱式獲取,或者通過一條lock table in row exclusive mode語句顯式獲取。這個鎖定可以防止其它會話獲取乙個共享鎖定、共享行獨佔鎖定或獨佔鎖定;
表共享鎖定:通過lock table in share mode語句顯式獲得。這種鎖定可以防止其它會話獲取行獨佔鎖定(insert、update或delete),或者防止其它表共享行獨佔鎖定或表獨佔鎖定,它允許在表中擁有多個行共享和表共享鎖定。該鎖定可以讓會話具有對錶事務級一致性訪問,因為其它會話在你提交或者回溯該事務並釋放對該錶的鎖定之前不能更改這個被鎖定的表;
表共享行獨佔:通過lock table in share row exclusive mode語句顯式獲得。這種鎖定可以防止其它會話獲取乙個表共享、行獨佔或者表獨佔鎖定,它允許其它行共享鎖定。這種鎖定類似於表共享鎖定,只是一次只能對乙個表放置乙個表共享行獨佔鎖定。如果a會話擁有該鎖定,則b會話可以執行select for update操作,但如果b會話試圖更新選擇的行,則需要等待;
表獨佔:通過lock table in exclusive mode顯式獲得。這個鎖定防止其它會話對該錶的任何其它鎖定。
事務隔離級別
儘管資料庫為使用者提供了鎖的dml操作方式,但直接使用鎖管理是非常麻煩的,因此資料庫為使用者提供了自動鎖機制。只要使用者指定會話的事務隔離級別,資料庫就會分析事務中的sql語句,然後自動為事務操作的資料資源新增上適合的鎖。此外資料庫還會維護這些鎖,當乙個資源上的鎖數目太多時,自動進行鎖公升級以提高系統的執行效能,而這一過程對使用者來說完全是透明的。
ansi/iso sql 92標準定義了4個等級的事務隔離級別,在相同資料環境下,使用相同的輸入,執行相同的工作,根據不同的隔離級別,可以導致不同的結果。不同事務隔離級別能夠解決的資料併發問題的能力是不同的。
表 1 事務隔離級別對併發問題的解決情況
隔離級別 髒讀
不可重複讀
幻象讀第一類丟失更新
第二類丟失更新
read uncommited 允許
允許 允許
不允許 允許
read committed
不允許 允許
允許不允許 允許
repeatable read
不允許不允許 允許
不允許不允許
serializable
不允許不允許
不允許不允許
不允許
事務的隔離級別和資料庫併發性是對立的,兩者此增彼長。一般來說,使用read uncommited隔離級別的資料庫擁有最高的併發性和吞吐量,而使用serializable隔離級別的資料庫併發性最低。
sql 92定義read uncommited主要是為了提供非阻塞讀的能力,oracle雖然也支援read uncommited,但它不支援髒讀,因為oracle使用多版本機制徹底解決了在非阻塞讀時讀到髒資料的問題並保證讀的一致性,所以,oracle的read committed隔離級別就已經滿足了sql 92標準的repeatable read隔離級別。
sql 92推薦使用repeatable read以保證資料的讀一致性,不過使用者可以根據應用的需要選擇適合的隔離等級。
資料庫事務併發問題
多個事務同時訪問資料庫時候,會發生下列5類問題,包括3類資料讀問題 髒讀,不可重複讀,幻讀 2類資料更新問題 第一類丟失更新,第二類丟失更新 1,髒讀 dirty read a事務讀取b事務尚未提交的更改資料,並在這個資料基礎上操作。如果b事務回滾,那麼a事務讀到的資料根本不是合法的,稱為髒讀。在o...
資料庫中事務併發問題
對於同時執行的多個事務,當這些事務訪問資料庫中相同的資料時,如果沒有採取必要的隔離機制。就會導致各種併發問題 資料庫事務的隔離性 資料庫系統必須具有隔離併發執行各個事務的能力,使它們不會互相影響,避免各種併發問題。乙個事務與其他事務隔離的程度稱為隔離級別。資料庫規定了多種事務隔離級別,不同隔離級別對...
資料庫的事務和併發問題
事務 transaction 是併發控制的基本單位。所謂的事務,它是乙個操作序列,這些操作要麼全部執行,要麼全部都不執行。比如,銀行轉賬,從乙個賬號扣錢,然後另乙個賬號餘額增加,這兩個操作要麼都執行,要麼都不執行。這兩個操作組合在一起就是事務。資料庫事務有嚴格的定義,它必須同時滿足4個特性 原子性,...