併發事務的問題和隔離級別

事務的ACID特性

原子性(Atomicity): 事務是最小的執行單位,不允許分割。事務的原子性確保動作要麼全部完成,要麼完全不起作用。
一致性(Consistency): 執行事務前後,數據保持一致,多個事務對同一個數據讀取的結果是相同的。
隔離性(Isolation): 併發訪問數據庫時,一個用戶的事務不被其他事務所幹擾,各併發事務之間數據庫是獨立的。
持久性(Durability): 一個事務被提交之後。它對數據庫中數據的改變是持久的,即使數據庫發生故障也不應該對其有任何影響。

併發事務的問題

  • 丟失修改(Lost to modify): 事務A、B同時訪問數據,A修改了這個數據後,B也修改了,則A的修改結果就丟失了。
  • 髒讀(Dirty read): 事務A對數據進行了修改,修改沒有提交時,事務B讀取這個未提交的“髒數據”。
  • 不可重複讀(Unrepeatableread): 事務A內兩次讀同一數據期間,事務B修改了該數據,則A內兩次讀到的數據不一樣。
  • 幻讀(Phantom read): 事務A讀取數據期期間,事務B插入或刪除了幾行記錄。在隨後的查詢中,A發現記錄多了火燒了,就好像發生了幻覺一樣,所以稱爲幻讀。

不可重複讀和幻讀區別:
出現不一致的細粒度不同,不可重複讀是A第二次讀一條記錄發現某些列的值被修改,幻讀的重點在於A發現增多或減少幾行記錄

隔離級別

在數據庫事務中,爲保證併發數據讀寫的正確性而提出的定義,它並不是MySQL專有的概念,而是源於ANSI/ISO制定的SQL-92標準。

每種關係型數據庫都提供了各自特色的隔離級別實現,以最常見的MySQL InnoDB引擎爲例,它是基於MVCC(Multi-Versioning Concurrency Control)和鎖的複合實現,按照隔離程度從低到高,MySQL事務隔離級別分爲四個不同層次:

  • 讀未提交(Read uncommitted):一個事務能夠看到其他事務尚未提交的修改,是最低的隔離水平,可能出現髒讀、幻讀或不可重複讀。。
  • 讀已提交(Read committed):保證不會看到未提交前的中間性狀態,不保證再次讀取時能夠獲取同樣的數據,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生
  • 可重複讀(Repeatable reads):保證同一個事務 對同一字段的多次讀取結果是一致的,是MySQL InnoDB引擎的默認隔離級別,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生
  • 串行化(Serializable),所有的事務依次逐個執行,是最高的隔離級別,完全服從ACID,可以防止髒讀、不可重複讀以及幻讀。意味着讀要獲取共享讀鎖,更新要獲取排他寫鎖,如果SQL使用WHERE語句,還會獲取區間鎖 (MySQL以GAP鎖形式實現,可重複讀級別中默認也會使用,所以MySQ的默認隔離級別也可以防止幻讀)。

悲觀鎖和樂觀鎖

悲觀鎖一般利用類似SELECT … FOR UPDATE這樣的語句對數據加鎖,避免其他事務修改數據。樂觀鎖則與Java併發包中的AtomicFieldUpdater類似,也是利用CAS機制,並不會對數據加鎖,而是通過對比數據的時間戳或者版本號,來實現樂觀鎖需要的版本判斷。 MVCC本質就可以看作樂觀鎖機制,而排他性的讀寫鎖、雙階段鎖等則是悲觀鎖的實現。

參考

《Java核心技術36講》
《MySQL必知必會》

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