1. 程式人生 > >事務的四個特性,以及在並發環境下可能引發的一些問題

事務的四個特性,以及在並發環境下可能引發的一些問題

每次 技術 如同 讀取 pda com 屬性 發的 刪除

原子性

    整個事務中的所有操作,要麽全部完成,要麽全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。

一致性

    一個事務可以封裝狀態改變(除非它是一個只讀的)。事務開始到結束必須從一個一致的狀態到另一個一致的狀態,不管在任何給定的時間並發事務有多少。
    也就是說:如果事務是並發多個,系統也必須如同串行事務一樣操作。其主要特征是保護性和不變性(Preserving an Invariant),以轉賬案例為例,假設有五個賬戶,每個賬戶余額是100元,那麽五個賬戶總額是500元,如果在這個5個賬戶之間同時發生多個轉賬,無論並發多少個,比如在A與B賬戶之間轉賬5元,在C與D賬戶之間轉賬10元,在B與E之間轉賬15元,五個賬戶總額也應該還是500元,這就是保護性和不變性。

隔離性

    隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用系統。這種屬性有時稱為串行化,為了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。

持久性

    在事務完成以後,該事務對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。
    簡單介紹實現持久性的一種思想:
    WAL 的中心思想是對數據文件 的修改(它們是表和索引的載體)必須是只能發生在這些修改已經 記錄了日誌之後 -- 也就是說,在日誌記錄沖刷到永久存儲器之後. 如果我們遵循這個過程,那麽我們就不需要在每次事務提交的時候 都把數據頁沖刷到磁盤,因為我們知道在出現崩潰的情況下, 我們可以用日誌來恢復數據庫:任何尚未附加到數據頁的記錄 都將先從日誌記錄中重做(這叫向前滾動恢復,也叫做 REDO) 然後那些未提交的事務做的修改將被從數據頁中刪除 (這叫向後滾動恢復 - UNDO)。

1.臟讀

    A事務讀取B事務尚未提交的更改數據,並在這個數據的基礎上進行操作,這時候如果事務B回滾,那麽A事務讀到的數據是不被承認的。

2.不可重復讀

    不可重復讀是指A事務讀取了B事務已經提交的更改數據。假如A在取款事務的過程中,B往該賬戶轉賬100,A兩次讀取的余額發生不一致。

3.幻讀

    A事務讀取B事務提交的新增數據,會引發幻讀問題。幻讀一般發生在計算統計數據的事務中,例如銀行系統在同一個事務中兩次統計存款賬戶的總金額,在兩次統計中,剛好新增了一個存款賬戶,存入了100,這時候兩次統計的總金額不一致。 
    註意:不可重復讀和幻讀的區別是:前者是指讀到了已經提交的事務的更改數據(修改或刪除),後者是指讀到了其他已經提交事務的新增數據。對於這兩種問題解決采用不同的辦法,防止讀到更改數據,只需對操作的數據添加行級鎖,防止操作中的數據發生變化;二防止讀到新增數據,往往需要添加表級鎖,將整張表鎖定,防止新增數據(oracle采用多版本數據的方式實現)。

4.第一類丟失更新

    A事務撤銷時,把已經提交的B事務的更新數據覆蓋了。 

5.第二類丟失更新

    A事務覆蓋B事務已經提交的數據,造成B事務所做的操作丟失 。

為了解決上述問題,數據庫通過鎖機制解決並發訪問的問題。根據鎖定對象不同:分為行級鎖和表級鎖;根據並發事務鎖定的關系上看:分為共享鎖定和獨占鎖定,共享鎖定會防止獨占鎖定但允許其他的共享鎖定。而獨占鎖定既防止共享鎖定也防止其他獨占鎖定。為了更改數據,數據庫必須在進行更改的行上施加行獨占鎖定,insert、update、delete和selsct for update語句都會隱式采用必要的行鎖定。

但是直接使用鎖機制管理是很復雜的,基於鎖機制,數據庫給用戶提供了不同的事務隔離級別,只要設置了事務隔離級別,數據庫就會分析事務中的sql語句然後自動選擇合適的鎖。

不同的隔離級別對並發問題的解決情況如圖:

技術分享圖片

事務的四個特性,以及在並發環境下可能引發的一些問題