隨著資訊技術的發展,工程師的面試越來越五花八門,面試過程問什麼都不足為奇,不過仍有些問題能夠事先準備,這些問題不僅常問也很實用,除了能夠應付面試之外,也能增加個人實力。
本文記錄後端工程師面試時經常會問到的資料庫 ACID 原則,並以實際範例作為說明,以讓人能夠對 ACID 有足夠的理解,避免死背。
A - Atomicity - 原子性
認識 ACID 之前,必須先理解何謂 transaction(或稱交易、事務)。
關於何謂 Transaction 可以先參考以下引用:
Transactions are atomic units of work that can be committed or rolled back.
A transaction is an indivisible logical unit of work in a database management system, allowing you to represent multiple operations as a single step.
簡單來說,任何要交給資料庫執行的工作,例如新增、刪除、修改、查詢等操作,都是 transaction 。每個 transaction 內可以包含 1 至多個對資料庫的操作,且每 1 個 transaction 都是不可被分割(indivisible / atomic)執行的工作單位。
譬如以下 MySQL 的 SQL 是 1 個 transaction, 含有 2 個 UPDATE 操作,模擬 1 個使用者在 1 個 transaction 內存錢 2 次的情況:
START TRANSACTION;
UPDATE users SET money = money + 100 WHERE id = 1;
UPDATE users SET money = money + 200 WHERE id = 1;
COMMIT;
所謂的不可分割(indivisible)或是原子性(atomicity), 指的就是每個 transaction 不論裡面包含的操作多寡,只能全部操作都一起成功或者一起失敗,所以上述的 SQL 範例,最終只可能是 id 1 的使用者 money 存款增加 300, 或者 transaction 失敗後, money 會 rollback transaction 到最近的狀態,就像沒有執行過任何 transaction 一樣,絕對不會有部分成功導致最後存款只有增加 100 的情況。
Atomicity 保證 transaction 的執行成功與否不會有模糊的界線存在。
為什麼我們執行單一 SQL 語句(statement)時,不需要特別寫 START TRANSACTION
?
順帶一提,包含 MySQL, PostgreSQL 等資料庫,都有實作所謂的 autocommit
, 該功能會自動將我們送出去的 SQL 語句以 START TRANSACTION
與 COMMIT
包裝起來,所以執行單一 SQL 語句時不需特別加 START TRANSACTION
的原因在此。
By default, MySQL runs with autocommit mode enabled. This means that, when not otherwise inside a transaction, each statement is atomic, as if it were surrounded by START TRANSACTION and COMMIT.
C - Consistency - 一致性
Consistency ensures that a transaction can only bring the database from one valid state to another, maintaining database invariants any data written to the database must be valid according to all defined rules, including constraints , cascades , triggers , and any combination thereof. This prevents database corruption by an illegal transaction, but does not guarantee that a transaction is correct.
Consistency 指的是資料必須遵守一致的規範,例如我們定義資料表(table)時,必須指定其資料型態(data type)或者為特定資料表欄位(column)設定檢查規則(check constraints)等等,任何不符合規範的資料,都會導致 transaction 失敗, Consistency 負責確保每個 transaction 造成的資料狀態改變都是合規的,另外值得一提的是, Consistency 並不保證 transaction 的結果是正確的。
例如以下 MySQL 資料表的建立,就使用 CHECK CONSTRAINTS 檢查資料,確保 c1 值大於 0 小於 32:
CREATE TABLE `t1` (
`id` int NOT NULL,
`c1` int DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT `c1_lt32` CHECK ((`c1` < 32)),
CONSTRAINT `c1_gt0` CHECK ((`c1` > 0))
) ENGINE=InnoDB;
如果我們試圖為 t1 資料表新增 1 組 c1 欄位為 0 的數據:
INSERT INTO t1(id, c1) VALUES (1, 0);
該操作就會因為違反 Consistency 的規範,造成以下錯誤:
Error Code: 3819. Check constraint 'c1_gt0' is violated.
I - Isolation - 交易隔離
Multiple concurrently executing transactions should be able to run without interference, as if there were no other transactions executing at the same time.
由於同一時間可能有多個 transaction 正在進行,因此 isolation 指的是交易間並不會有彼此干擾的情況。
而為了確保 transaction 間不彼此干擾, isolation 有不同的級別(levels),每個級別各自定義 transaction 執行時,如何處理同一時間其他 transaction 所造成的資料狀態改變:
- Repeatable Read
- Read Committed
- Read Uncommitted
- Serializable
這些級別的差異,可以詳見 Backend 淺談 database Transaction Isolation Levels 一文。
也由於 isolation 的隔離特性,因此多個 transactions 對同一筆資料或欄位進行更新時,請記得使用 LOCK 。
D - Durability - 持久性
Once a transaction has been committed, all database state modifications have to be persisted on disk and be able to survive power outages, system failures, and crashes.
最後, Durability 則是指一旦 transaction 成功執行之後,就該被持久地保存,甚至是斷電、系統錯誤、當機等等,都不會影響該筆數據。
References
https://dev.mysql.com/doc/