解說SQL的Transaction與隔離層級
什麼是Transaction?
Transaction,大陸有人翻譯為交易或事務,但都同一個意思。
它是一個執行過程中的一個邏輯單位。比方說SELECT、INSERT、UPDATE,當中也可能包含多個行為,比方說查詢後更新。為了確保資料庫的交易在各種情況下都是維持正確性,交易有四個特性,也就是俗稱的ACID。1. Atomicity 原子性
原子性主張交易必須要維持統一不變的狀況,交易必須是全數成功,不然就得是全部失敗。
舉例: 假設你是消費者,進行消費後在前台的交易系統有存入這筆交易,但是系統的交易後台卻沒有這筆交易,顯示更新這個功能只做了一半,交易的行為破壞了原子性。
2. Consistency 一致性
一致性主張,交易前與交易後都必須要遵守完整性的規範,比方說店家前台的交易系統與系統後台必須要維持一致性,交易的結果不統一破壞了一致性。
3. Isolation 隔離性
隔離性代表了交易不應該互相干擾,假設你看到的戶頭有1000元,而你在領800去吃飯時,剛好電費同時扣款導致你無法進行交易。不夠嚴謹的隔離性後續會產生許多問題,等一下會一一介紹。
4. Durability 永久性
永久性意味對於資料的寫入是永久的,即使系統故障也不會丟失資料。
這些規範看起來很合理,但未必適合每種商業場景,實際上還是要多多考慮實際上的商業場景在做出決定。就好比高可用性與系統效能永遠都是一個無法兼得的選項一樣。端看你要如何取捨。
三種SQL隔離性會產生的問題
設定了錯誤的隔離層級會造成許多系統上難維護的課題,特別是在多執行緒的場景,使用Trasaction特性要特別謹慎。常見的隔離性不正確會有以下問題:
1. Dirty Read 髒讀
指一筆交易在處理過程中讀取了另外一個交易”未提交”的數據。
舉例:
帳戶原有1000,
A會
- 對帳戶領500
- 對帳戶存500
B會 - 讀取帳戶餘額。
在兩者同時處理的併發情況下可能發生: A1 > B >A2
也就是說帳戶其實錢並沒有減少,但在B的視角中,可能產生帳戶少了500元的結果。
2. Non-Repeatable 不可重複讀
指一個交易範圍內,多次查詢某個數據,卻得到不同的結果。
舉例:
呈上例,B初次讀取時得到了500,但過一下子讀取後又得到了1000。兩次結果不一致。
3. Phantom Read 幻讀
一個交易範圍內,多次查詢某個數據,卻得到不同的資料筆數。
四種隔離層級
1. Read Uncommitted:
這個隔離層級可以讀取尚未commit的資料,因為資料包含為commit的資料,所以可能會產生以上三種問題。
這種隔離層級可能產生:
- 髒讀
- 不可重複讀
- 幻讀
2. Read Committed:
這個隔離層級只允許讀取其他 transaction commit 過的資料,可以解決髒讀的問題,
不過如果一個 transaction 的兩個 SELECT 語法間有另一個交易 commit 了新資料,
會造成第一次讀取與第二次讀取結果不一致的問題,也就是上面介紹過的不可重複讀。
這種隔離層級可能產生:
- 不可重複讀
- 幻讀
3. Repeatable Read
同一個 transaction 內,除非自己修改,否則多次 SELECT 的結果都會相同,解決了不可重複讀的問題。
這種隔離層級可能產生:
- 幻讀
4. Serializable
在一開始提過,是一個用效能換取一致性的隔離層級,
讓所有 transaction 序列化執行,避免併發可能會造成的問題。
可解決問題但效能低落。
以上