想像一下你在咖啡廳打工,一個服務生在廚房查蛋糕庫存,另一個則在幫新客人下蛋糕單。在理想世界裡,他們應該都看到一樣的蛋糕數量,這樣才不會出現像「重複預訂」這種烏龍。但現實世界裡,並行操作就可能出現各種問題啦。
這裡有三個最常見的麻煩:
Dirty Read(髒讀): 一個查詢看到另一個查詢還沒 commit 的變更。如果這些變更被 rollback,第一個查詢就像剛去面試的大學生一樣天真。
Non-Repeatable Read(不可重複讀): 一個查詢兩次讀同一筆資料,但中間有人改了它。就像你去車站看火車時刻表,過一分鐘回來發現車被取消了。或者你找錢時票被別人買走了 XD
Phantom Read(幽靈讀): 一個查詢看到一部分資料,但兩次查詢間有人插入新資料,結果就變了。就像你公司標案沒中,結果除了你跟市長老婆的標案外其他都被取消了。
交易隔離等級
既然知道這些問題,來看看 PostgreSQL 給我們什麼工具來解決——交易隔離等級。這就像幫並行交易訂規矩。隔離等級越高,交易互相干擾的機會就越小。但這樣會犧牲「服務速度」,也就是效能啦。
PostgreSQL 的隔離等級
Read Uncommitted(讀未提交資料):
- 允許讀到還沒 commit 的變更(對,這就是髒讀的經典範例)。
- 在 PostgreSQL 裡其實會被當成
Read Committed,所以純正的 Read Uncommitted 不支援。PostgreSQL 覺得這太不靠譜了,直接拒絕實作。
Read Committed(讀已提交變更):
- 避免髒讀。
- 交易只能看到執行時已經 commit 的資料。
- 但還是可能出現
Non-Repeatable Read跟Phantom Read。
Repeatable Read(可重複讀):
- 保證你讀到的資料,在這次交易期間都不會變。
- 避免髒讀跟不可重複讀。
- 但幽靈資料還是有可能出現。
Serializable(可序列化):
- 保證交易執行起來就像一個一個排隊來一樣。
- 三種問題都能避免:髒讀、不可重複讀、幽靈資料。
- 最嚴格——也是最慢——的隔離等級。
為什麼交易隔離很重要?
想像一個網路商店的資料庫,成千上萬的用戶同時下單。如果隔離等級沒設好,會出現一堆衝突:從「商品消失」到「訂單重複」都有可能。
選對隔離等級可以幫你搞定交易競爭,讓效能跟資料正確性取得平衡。舉例來說:
- 分析系統通常選最低隔離等級(像 Read Committed),因為資料精確度沒那麼重要。
- 金融系統就會選 Serializable,這樣才不會算錯錢或重複扣款。
隔離等級的應用範例
- Read Committed
這個等級保證你不會讀到可能被 rollback 的資料。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
-- 讀取帳戶資料。
SELECT balance FROM accounts WHERE account_id = 1;
-- 如果有其他交易更新這個餘額,這裡會馬上看到新資料。
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;
- Repeatable Read
這個等級保證你讀到的資料,在這次交易期間都不會變。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
-- 讀取帳戶資料。
SELECT balance FROM accounts WHERE account_id = 1;
-- 就算有其他交易更新這個餘額,你也看不到變化。
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;
- Serializable
這個等級下,交易就像系統裡只有你一個人在動作。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
-- 讀取帳戶資料。
SELECT balance FROM accounts WHERE account_id = 1;
-- 任何其他想改這筆資料的交易都會被鎖住,直到你這筆結束。
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;
怎麼選隔離等級?
選隔離等級要看你的需求:
- 如果速度比精確重要,而且你能接受幽靈資料——選
Read Committed。 - 如果精確重要,但還想保有高效能——用
Repeatable Read。 - 如果你要 100% 資料正確,就算慢也沒關係——那就
Serializable。
小心喔!高隔離等級可能會造成鎖死,讓系統變慢。最聰明的做法就是在效能跟資料一致性間找到平衡點。
GO TO FULL VERSION