聊聊資料庫的事務隔離級別

qing_yun發表於2023-10-11

前幾天一個金融行業的朋友和我討論資料庫選型的事情,他們在選擇分散式資料庫的時候發現這些資料庫支援的事務隔離級別與Oracle有較大差異,有位領導認為對事務隔離級別的支援能力說明了資料庫在併發處理方面的能力,因此要在選型中佔有比較高的分值,甚至要在較高事務隔離級別下測試資料庫的併發效能。他對此持不同的看法。

資料庫事務隔離級別的概念最早是在1981年由IBM的Jim Gray等人提出的,他們在論文《The Notions of Consistency and Predicate Locks in a Database System》中定義了四種隔離級別,分別是:

  • 讀未提交(Read uncommitted):最低的隔離級別,允許一個事務讀取另一個未提交事務的資料,可能導致髒讀、不可重複讀、幻讀等問題。

  • 讀提交(Read committed):目前被應用最為廣泛的使用的事務隔離級別,只允許一個事務讀取另一個已提交事務的資料,可以避免髒讀,但不能避免不可重複讀、幻讀等問題。

  • 可重複讀(Repeatable read):較高的隔離級別,保證一個事務在執行過程中對同一資料的多次讀取結果都是一致的,可以避免髒讀、不可重複讀,但不一定能避免幻讀等問題。

  • 序列化(Serializable):最高的隔離級別,要求事務序列執行,不允許併發訪問和修改同一資料,可以避免髒讀、不可重複讀、幻讀等所有問題,但效能最差。

資料庫的多種事務隔離級別是想為應用開發者提供不同的併發控制,從而適應各種不同的應用應用場景。這在T/S架構流行的80/90年代應用廣泛。那時候所有的計算都只能在主機或者小型機上完成,因此資料庫提供的這個功能可以大大簡化應用開發。C/S架構出現後,特別是後來的三層架構大行其道的時代之後,Read Committed變成了最為常用的事務隔離級別,其他事務隔離級別大多數都基本上不用了。比Read Committed更高的事務隔離級別被前置到應用前端或者中間層來實現了。

更高的事務隔離級別的最著名的例子就是分頁查詢,在RC隔離級別下,哪怕是在一個事務中,我們在前端分頁查詢同一個資料時,都會看到“髒資料”,因為這些資料在我們讀的時候也會有人同時在修改和寫入新的滿足條件的資料。對於這種方式的處理方法一般來說就是容忍“髒資料”,網際網路應用一般都是這樣處理的。而對於資料一致性要求很高的財務系統,則一般採用在中間層快取資料或者使用全域性臨時表快取資料的方式來確保資料的一致性。

現在的應用較少的透過事務隔離級別來處理這種高一致性要求的資料的主要原因還是因為技術發展了,多層架構讓中間層有了更為強大的可擴充套件的處理能力,而資料庫本身也因為硬體的發展能夠承受大量的臨時表儲存資料的需求。這些應用層實現的更高事務隔離級別的應用需求往往比透過資料庫實現有更高的靈活性,因此比RC更高的事務隔離級別實際上在我們的大多數應用中已經早就沒有人使用了。

可能有朋友要問,為什麼MySQL的預設事務隔離級別不是RC而是RR呢?這和MySQL資料庫的歷史有關,MySQL資料庫因為早期的BINLOG複製不支援RAW格式的問題而必須選擇RR,如果使用RC無法確保複製資料的一致性。但是用了RR這種事務隔離級別,又會引起資料庫的併發效能受到影響,因此MySQL引入了GAP LOCK這種特殊的鎖機制,來降低RR對資料庫併發的效能影響。哪怕是引入了GAP LOCK,在RR隔離級別下,對於SELECT … FOR UPDATE的操作,RR隔離級別也會比RC有更多的鎖阻塞,因此我們建議MySQL使用者如果BINLOG複製使用能夠RAW的情況下,還是把預設的事務隔離級別設定為RC。

回到文章頭上的那個金融交易系統的例子,這個例子是十分典型的RC事務隔離級別就是最佳隔離級別的例子,在此種應用場景下,還把事務隔離級別看作是資料庫選型的重要因素,就有點不太合適了。

分散式資料庫最早的初衷就是提高併發交易的能力,因此它們在較高事務隔離級別方面天然就處於劣勢的,用這種因素去選型,肯定就與選型的初衷背道而馳了。實際上與前面所說的一樣,目前我們的應用開發大多數都基於RC事務隔離級別。更高的事務隔離級別的應用需求大多數都在應用中去處理了,或者說哪怕要用資料庫來實現,這種應用場景應該也不會是有很高併發的。因此在較高事務隔離級別下測試併發效能對於大多數使用者來說確實是沒有太大必要了。

來自 “ 白鱔的洞穴 ”, 原文作者:白鱔;原文連結:https://mp.weixin.qq.com/s/D-bWrQ80rrW4clrCp9RQhg,如有侵權,請聯絡管理員刪除。

相關文章