Home
Posts
Categories
Series
Tags
About
交易隔離等級
postedOn: 2026-4-12   updatedOn: 2026-4-12   includedIn: 程式
wordsCount: 1245   readingTime: 3 mins   viewers:

What we talk this ?

在不同的商業模式下,注重的核心不同,有些要速度,可接受不準確,有些要資料精準,可接受慢一點,有些則絕對不能錯, 所以可透過隔離等級調整資料庫行為,並加上sql語法的調整來做到目標

Isolation Level 交易隔離等級

併發性能&資料一致性成反比

隔離級別 Dirty Read Non-Rep. Read Phantom Read Write Skew 實作機制 / 特性 適用情境
Read Uncommitted ✅ 可能 ✅ 可能 ✅ 可能 ❌ 可能 幾乎不加鎖,直接讀取記憶體中的變動 極端效能需求 (極少用)
Read Committed ❌ 不會 ✅ 可能 ✅ 可能 ❌ 可能 每次Statement執行時取得新快照 PostgreSQL, SQL Server預設
Repeatable Read ❌ 不會 ❌ 不會 PostgreSQL❌ ,MySQL❗可能 可能 Transaction時固定快照 MySQL 預設 PostgreSQL (RR)SQL Server (SI)透過快照機制已經完全解決幻讀。**MySQL (RR)**則是在快照讀下解決,但當前讀(如UPDATE)仍可能觸發幻讀。
Serializable ❌ 不會 ❌ 不會 ❌ 不會 不會 SSI (感應式序列化) 或兩階段鎖定 (2PL) 財務清算、嚴格一致性要求
Snapshot Isolation(非標準) ❌ 不會 ❌ 不會 不會 可能 以快照為準,PostgreSQL 的 RR 實質為此級別 高併發且需避免幻讀,但要注意寫入衝突
Linearizable(分散式) ❌ 不會 ❌ 不會 ❌ 不會 不會 結合時鐘同步,保證「真實時間」的全域順序 分散式鎖 (etcd)、全域資料庫 (Spanner)

1.Read Uncommitted (RU)

問題:髒讀 Dirty Read

還沒commit的東西,就可以讀到

適用:效能第一

Transaction A Transaction B
BEGIN;SELECT money FROM customer WHERE id = 1;/* money = 100 */
BEGIN;UPDATE customer SET money = 2000 WHERE id = 1;/* money = 2000 */
SELECT money FROM customer WHERE id = 1;/* money = 2000 */
髒讀 (Dirty Read)/* money = 2000 *//* money 實際為 100,但 Transaction A 以為是 2000 */ ROLLBACK;/* money = 100 */

下個級別有改善: 交易要做commit才會被其他交易看到

2.Read Committed(RC) (Oracle,PostgreSQL,SQL Server預設)

問題:不可重複讀 Non-repeatable read

一個交易內可能兩次無法讀到一樣的東西

A交易時間較長,讀取後,B交易快速完成,導致A交易再次讀取會讀到不一樣的東西(資料的即時性)

適用:高流量

如果前面的檢查邏輯過了,後面再次查詢,邏輯上沒有連貫性

Transaction A Transaction B
BEGIN;SELECT money FROM customer WHERE id = 1;/* money = 500 */
BEGIN;UPDATE customer SET money = 2000 WHERE id = 1;/* money = 2000 */
COMMIT;/* money = 2000 */
SELECT money FROM customer WHERE id = 1;/* money = 2000 */
無法重覆讀取到相同結果 (non-repeatable read)第一次讀到 money = 500第二次讀到 money = 2000

下個級別改善: 讀取過的列,其他交易來做變更,我一樣還會讀到同樣的資料

3.Repeatable Read(RR) (MySQL的預設)

問題:幻讀 Phantom Read

因為交易做快照,來保證看到同樣的東西(MVCC),但實際上是有變更,資料庫內有多版本

Transaction A Transaction B
BEGIN;SELECT * FROM product ;/* id=1 , price= 300 */
BEGIN;INSERT INTO product VALUES (2, 500);COMMIT;
SELECT * FROM product ;/* id=1 , price= 300 *//* id=2 , price= 500 */
幻讀 (Phantom Read)兩次取得的筆數不相同

Phantom Read (幻讀)

- **PostgreSQL RR**:採用 Snapshot Isolation。事務開始那一刻,整個資料庫的狀態就固定了,**絕對讀不到**後來插入的行。所以 PG 的 RR 是**不會**有幻讀的。
- **MySQL RR**:雖然有 Gap Lock,但它是為了保護「寫入」和「強致讀取」。如果你只用普通的`SELECT`(快照讀),雖然不會看到新行,但如果你接著執行`UPDATE`或`INSERT`碰到新行,就會產生衝突或讓新行現身。因此 MySQL 的 RR**並未百分之百**解決幻讀。

4.Serializable 序列化:

交易期間,不給讀取,高流量災難

適用:精准度第一