數據庫筆記4---事務特性ACID、隔離級別、事務併發問題小結


一、什麼是事務

  事務(Transaction)是指一組原子性的SQL操作,或者說是一個獨立的工作單元,所有操作必須全部成功完成,如果其中有任何一條語句因爲崩潰或其他原因無法執行,那麼所有更改都會被撤消。可以通俗理解爲:事務內的語句,要麼全部執行成功,要麼全部執行失敗,即:“all-or-nothing” 。

  在MySQL中,事務支持是在存儲引擎層實現的;並不是所有引擎都支持事務,如 MyISAM 就不支持,InnoDB 就支持。


二、事務的四個特性(ACID)

1. 原子性(Atomicity)

  一個事務必須被視爲一個不可分割的最小工作單元,整個事務中的所有操作要麼全部執行成功,要麼全部失敗回滾,回滾到執行指令前的數據狀態。

2. 一致性(Consistency)

  事務的執行使數據庫總是從一個一致性狀態轉換到另外一個一致性狀態。

eg:拿轉賬來說,假設用戶A和用戶B兩者的錢加起來一共是20000,那麼不管A和B之間如何轉賬,轉幾次賬,事務結束後兩個用戶的錢相加起來應該還得是20000,這就是事務的一致性。

3. 隔離性(Isolation)

  隔離性是當多個用戶併發訪問數據庫時,比如操作同一張表時,數據庫爲每一個用戶開啓的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。即:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始之前就已經結束,要麼在T1結束之後纔開始,這樣每個事務都感覺不到有其他事務在併發地執行。

通過上面的解釋,我們能夠理解什麼是隔離性,不同的事務爲了避免互相干擾必須互相隔離,甚至完全地串行執行,這樣併發效率不高。所以SQL標準中定義了四種隔離級別(isolation level),每一種級別都規定了哪些是不可見的,哪些是事務內和事務間是可見的。通常較低級別的隔離可以執行更高的併發,系統的開銷也更低。

4. 持久性(Durability)

  當事務正確完成後,它對於數據的改變是永久性的。此時即使系統崩潰,修改的數據也不會丟失。


三、隔離級別和併發問題

  在許多事務處理同一個數據時,如果沒有采取適當的隔離級別,那麼併發處理數據時,會帶來一些的問題,即:髒讀 、不可重複讀 、幻讀。

1.丟失更新

  • 第一類丟失更新
      由於某個事務的回滾操作,參與回滾的舊數據將其他事務的數據更新覆蓋了。
時間序號 事務一 事務二
T1 開啓事務 開啓事務
T2 查詢賬戶money=1000 查詢賬戶money=1000
T3 存款100,money=1100
T4 轉賬100,money=900
T5 提交事務,money=900
T6 取消事務,回滾,money=1000
  • 第二類丟失更新
      一個事務提交時,把其他事務已提交的更新數據覆蓋,造成之前其他事務提交的更新丟失。即:事務T1 和事務T2 從數據庫中讀入同一數據並修改。事務T1 先提交,執行完成,然後事務T2 提交後覆蓋了事務T1 的提交的結果,導致事務T1 的修改丟失。
    在這裏插入圖片描述

2.髒讀

  髒讀(Dirty Read)是指在一個事務(T1)處理過程裏讀取了另一個未提交事務(T2)中的數據。如果事務(T2)由於某種原因被撤銷,它修改過的數據恢復原值,那麼事務(T1)讀到的數據與數據庫中的數據不一致,是不正確的數據,稱作“髒”數據。
在這裏插入圖片描述

3.幻讀(phantom read,也叫虛讀)

  一個事務內執行兩次查詢,第二次結果集包含第一次中沒有或某些行已經被刪除的數據,造成兩次結果不一致,只是另一個事務在這兩次查詢中間插入或刪除了數據造成的。

在這裏插入圖片描述

4.不可重複讀

  不可重複讀,顧名思義,即在一個事務內 多次讀取同一行數據時讀出來的結果不一樣。因爲在讀操作的中間正好有另一個事務更新了該行數據,導致兩次讀取的結果不一樣,不可被信任。

案例:事務T1在讀取某一行數據,而事務T2立馬修改了這行數據並且提交事務給數據庫,事務T1再次讀取該數據就得到了不同的結果,發生了不可重複讀。

注意點一:不可重複讀和髒讀的區別:髒讀是某一事務讀取了另一個事務未提交的髒數據,而不可重複讀則是讀取了前一事務提交的數據。

注意點二:幻讀和不可重複讀有些類似。不可重複讀關注的是對同一個數據項是否有update操作;幻讀針對的是insert和delete,是對一批數據整體(比如數據的個數)。


四、事務的隔離級別

  事務的隔離級別有4種,由低到高分別爲Read uncommitted 、Read committed 、Repeatable read 、Serializable 。不同的隔離級別有各自的特點:

√: 可能出現 ×: 不會出現

髒讀 不可重複讀 幻讀
Read uncommitted
Read committed ×
Repeatable read × ×
Serializable × × ×

1. 未提交讀(Read uncommitted)

  在Read uncommitted級別中,事務中的修改即使沒有提交,對其他事務也是可見的。這個級別會導致很多問題,比如:髒讀(Dirty Read)。性能上不必其他隔離級別好太多,但卻缺乏其他級別的很多好處,所以在實際應用中一般很少使用。

2.提交讀(Read committed)(可避免"髒讀")

  • 大多數數據庫系統的默認隔離級別都是Read committed(MySQL除外)。
  • 一個事務開始時,只能看到已經提交的事務所做的修改。即:一個事務從開始到提交前做的任何修改對其他事務都是不可見的。
  • 解決了“髒讀”問題。
  • 無法避免“不可重複讀”和“幻讀”問題。執行兩次同樣的查詢,可能會得到不一樣的結果。

3.可重複讀(Repeatable read)(可避免"髒讀"、“不可重複讀”)

  • MySQL中默認的隔離級別。
  • 該級別保證了同一個事務中多次讀取同一條記錄的結果是一致的。
  • 無法解決"幻讀"。InnoDB和XtraDB存儲引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)解決了幻讀問題。

4.串行化(Serializable )

  Serializable 是最高的隔離級別。它通過強制事務串行執行,可以避免髒讀、不可重複讀與幻讀。實際應用中很少用到這個隔離級別。

注意事項:

  1. 大多數數據庫默認的事務隔離級別是Read committed,但Mysql的默認隔離級別是Repeatable read。
  2. 隔離級別的設置只對當前鏈接有效。對於使用MySQL命令窗口而言,一個窗口就相當於一個鏈接,當前窗口設置的隔離級別只對當前窗口中的事務有效;對於JDBC操作數據庫來說,一個Connection對象相當於一個鏈接,而對於Connection對象設置的隔離級別只對該Connection對象有效,與其他鏈接Connection對象無關。
  3. 設置數據庫的隔離級別一定要是在開啓事務之前。

五、參考資料

1、《高性能MySQL》
2、什麼是事務?事務的四個特性以及事務的隔離級別
3、丟失更新,髒讀,不可重複讀,幻讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章