資料庫並發控制的核心在於隔離級別。本文系統梳理 ANSI SQL-92 定義的四大隔離級別、三大經典異常現象,並深入剖析 Oracle 獨特的「讀不阻塞寫、寫不阻塞讀」多版本一致性讀(MVCC)實作機制。
| 異常 | 場景描述 | 口訣 |
|---|---|---|
| 髒讀 | T1 修改未提交,T2 讀到;T1 回滾,T2 讀到無效資料 | 讀到未提交 |
| 不可重複讀 | T1 讀同一列兩次,中間 T2 修改並提交,兩次結果不同 | 同一查詢結果變 |
| 幻讀 | T1 按條件查兩次,中間 T2 插入符合條件新列,第二次多出列 | 查詢結果集變多 |
| 隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | 備註 |
|---|---|---|---|---|
| READ UNCOMMITTED | 允許 | 允許 | 允許 | 極少資料庫預設 |
| READ COMMITTED | 禁止 | 允許 | 允許 | Oracle、PostgreSQL、SQL Server 預設 |
| REPEATABLE READ | 禁止 | 禁止 | 允許 | MySQL InnoDB 預設 |
| SERIALIZABLE | 禁止 | 禁止 | 禁止 | 最高隔離,效能最差 |
Oracle **僅支援** READ COMMITTED(預設)與 SERIALIZABLE 兩種,不支援 READ UNCOMMITTED、REPEATABLE READ。
ORA-08177: can't serialize access for this transactionSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;(必須在事務第一條 DML 前執行)Oracle 透過 Undo Segment 保存舊版本資料塊,實現「讀不阻塞寫、寫不阻塞讀」。這與 SQL Server 預設使用鎖實現隔離(讀寫互斥)形成鮮明對比,是 Oracle 高併發效能的基石。
-- Session 1: 設定 SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT * FROM t WHERE id = 1; -- 假設回傳 name='A'
-- 暫停,不提交
-- Session 2: 修改並提交
UPDATE t SET name = 'B' WHERE id = 1;
COMMIT;
-- Session 1: 再次查詢
SELECT * FROM t WHERE id = 1; -- 仍回傳 'A'(快照隔離)
-- 嘗試更新同一列
UPDATE t SET name = 'C' WHERE id = 1; -- 拋 ORA-08177
-- Session 3: 新開事務(READ COMMITTED)
SELECT * FROM t WHERE id = 1; -- 看到 'B'(已提交版本)
INSERT/UPDATE/DELETE/MERGE)COMMIT/ROLLBACK)後,執行下一條 DMLSELECT 不會啟動事務。
V$TRANSACTION、V$UNDOSTAT 確保 Undo 表空間與 UNDO_RETENTION 滿足長查詢需求,避免 ORA-01555理解隔離級別不是背誦定義,而是預判業務場景下的並發行為,選擇最小代價滿足正確性的策略。