什麼是Database的ACID與一致性問題

目的

介紹ACID,並且針對其中的C(Consisitency)一致性提出常見的問題與解決問題的Lock用法

ACID

資料庫的ACID基本上就是四個字首的縮寫分別是

  • ATOMICITY
  • CONSISTENCY
  • ISOLATION
  • DURABILITY

在開始進入文章前需要先講解一個概念Transaction(交易/事務),Transaction代表著你的程式在這個過程中對資料庫做的操作

舉例:

今天會員購買了這個產品,則程式會對資料庫做一系列的操作包含
新增訂單資料
新增會員與訂單的關聯資料
更新商品銷售資料
則這系列的操作可稱為一個Transaction

若是以Java Spring中的Annotation來講解的話,若在method上標記Transaction則Spring會幫助你判斷此method中對資料庫的操作都為一個Transaction。

ATOMICITY (原子性)

一個Transaction中的全部操作被視為不可分割,代表要就全部完成或是全部取消。若是其中一個環節失敗則會全部回滾(Rollback)到此資料庫Transaction前的狀態。
原子性確保了資料庫的可使用性,當然當資料不再準確時資料庫基本上也不可以使用了

CONSISTENCY (一致性)

其實目前我對於網路上一致性的解釋上有些許混亂,網路上有兩種說法可能是與CAP理論的C一起解釋了,如何選擇就由客官們判斷了

  1. 資料庫在Transaction執行後資料都必須符合schema的規範,例如要執行Trigger或是constraint(Not null/Unique)
  2. 資料庫每個Transaction讀取一個數據的解果都是一樣的

第二個說法的補充

當資料滿足了原子性與隔離性,那在同步進行Transaction時,就算其中一個Transaction
提前完成,那資料也是可以滿足一致性的

ISOLATION (隔離性)

Transaction在確定提交以前,是看不到其他Transaction對這個資料的操作。

DURABILITY (持久性)

一但Transaction提交後,其作的修改將會永遠存在Database之中不能遺失

常見的一致性問題

現在各語言框架通常都已經將資料庫操作包裝好都符合ACID原則,開發者只要呼叫API即可使用,比較少會遇到一致性的問題,但是現在微服務盛行分佈式系統中可能會有好幾台資料庫,在這裡介紹基本以前常遇見的資料庫問題,或許在分佈式系統中可以也會遇到這些提高層級的一致性問題

遺失修改值

T1 -> x=50 -> UPDATE x -------------------> SELECT x -----> x = 100 (不符合預期值)
T2 --------------------> x=100-> UPDATE x ----------------> x = 100

讀取髒數據

T1 -> SELECT x -> x=50 -> UPDATE x --------------->ROLLBACK -> x = 100 (不符合預期值)
T2 ------------------------------- x=100 -> UPDATE x --------> x = 100

不可重複讀

若T2在操作中需要讀取兩次x則第二次取出的值會不同

T1 x=50 -> SELECT x -> x=100 -> UPDATE x -------------> x = 100 (不符合預期值)
T2 x=50 -> SELECT x --------------------- SELECT x ---> x = 100

幻影讀

T1 size = COUNT(x) = N --------- size = COUNT(x) --------> size = N+1 (不符合預期值)
T2 --------------------INSERT x--------------------------> size = N+1

敲黑板 畫重點

若是資料庫不符合ACID原則的話,上面四種情形會非常常見,還是要強調現在用的語言與框架大多已將這些問題包裝並且預防了,而這些問題不一定只會存在於資料庫中再多執行續或是分佈式系統也會常常遇到。

常見的一致性問題解法 - Lock

Lock顧名思義就是將Table或是Raw鎖住不讓其他Transaction使用,可以確保資料的一致性當然效能也會因為要等待Lock解鎖會受到影響,這也是需要考量的事情。

當我們在考慮加鎖時首先要考慮的是,Lock的粒子大小,粒子大小如果在資料庫的話就是Table與Row,今天明明只要鎖Row但是鎖了整張Table讓整個程式運轉下降的話那就不大妙了,而到底要使用哪一種就要看每個工程師的經驗與實力了,最重要的是在平行執行跟Lock的時間消耗做一個平衡

Lock的種類有兩種分別是

  • 排它 (Exclusive) - Write 通稱X鎖
  • 共享 (Shared) - Read 通稱S鎖

其中的兼容性如下

- x s
x x x
s x s

當加了x鎖(Write)那今天除了目前的Transaction其他都無法讀取和寫入此資料/表
當加了s鎖(Read)代表著今天除非我解了此鎖才可以繼續寫入不然今天每個人只能讀

如果在Database的操作中加上了鎖,那上一章節的一致性問題都可以逢刃而解,而Lock的更深入的操作就等哪一天我更深入探索Database之後再發一篇新文章搂!

參考資源

ACID Properties in DBMS
Wiki

關鍵字

  • Concurrency control
  • ACID

留言

這個網誌中的熱門文章

Java Lambda Map篇

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)