SQL Server 提供五種事務隔離等級,平衡資料一致性與並發效能。本文系統整理三大並發異常(髒讀、不可重複讀、幻影讀)、五大隔離等級解決範圍、設定語法與選擇決策指南。
| 異常 | 發生情境 | 後果 |
|---|---|---|
| 髒讀 | 交易 A 讀取交易 B 修改但未提交的資料 | 若 B 回滾,A 讀到的資料無效(髒資料) |
| 不可重複讀 | 交易 A 兩次讀取同一資料,中間交易 B 修改並提交 | A 兩次讀到不同值,邏輯判斷失效 |
| 幻影讀 | 交易 A 多次查詢同一範圍,中間交易 B 插入/刪除符合條件的列 | A 發現列數變化,如見鬼魅 |
| 隔離等級 | 髒讀 | 不可重複讀 | 幻影讀 | 機制 | 並發度 |
|---|---|---|---|---|---|
| READ UNCOMMITTED | ❌ 允許 | ❌ 允許 | ❌ 允許 | 無共享鎖,等同 NOLOCK | 最高 |
| READ COMMITTED (預設) | ✅ 防止 | ❌ 允許 | ❌ 允許 | 讀取已提交資料,釋放共享鎖 | 高 |
| REPEATABLE READ | ✅ 防止 | ✅ 防止 | ❌ 允許 | 持有共享鎖至交易結束 | 中 |
| SERIALIZABLE | ✅ 防止 | ✅ 防止 | ✅ 防止 | 範圍鎖,完全序列化 | 低 |
| SNAPSHOT | ✅ 防止 | ✅ 防止 | ✅ 防止 | MVCC 版本鏈,讀不阻寫 | 高(資源換並發) |
-- 會話 A
BEGIN TRAN
INSERT INTO Customer VALUES ('123','123')
WAITFOR DELAY '00:00:20'
COMMIT TRAN
-- 會話 B
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM Customer -- 立即看到 '123',若 A 回滾即為髒讀
相當於 WITH (NOLOCK)。適合:報表查詢可容忍髒資料、資料倉庫 ETL 階段掃描。
只見已提交資料。無法防止:同一交易中兩次查詢結果不同(不可重複讀)、範圍查詢列數變化(幻影讀)。
-- 會話 A SET TRANSACTION ISOLATION LEVEL REPEATABLE READ BEGIN TRAN SELECT * FROM Customer WHERE ID = 17 WAITFOR DELAY '00:00:30' SELECT * FROM Customer WHERE ID = 17 -- 兩次結果保證相同 COMMIT TRAN -- 會話 B (在 30 秒內) UPDATE Customer SET Title = 'd' WHERE ID = 17 -- 被阻塞等待 A 結束
持有共享鎖至交易結束,阻塞修改。無法防止幻影讀(新增列不受共享鎖保護)。
-- 會話 A
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
UPDATE Customer SET Title = '111'
WAITFOR DELAY '00:00:20'
COMMIT TRAN
-- 會話 B (在 20 秒內)
INSERT INTO Customer VALUES ('2','2') -- 被範圍鎖阻塞,避免幻影讀
最嚴格等級,並發度最低,易發生死鎖與逾時。僅用於極高一致性需求(如財務結帳)。
啟用資料庫選項:ALTER DATABASE SET ALLOW_SNAPSHOT_ISOLATION ON。
讀取資料快照(版本鏈),讀不阻寫、寫不阻讀。寫入衝突時以錯誤 3960 終止其中一交易(樂觀並發)。
SET TRANSACTION ISOLATION LEVEL
READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
| SNAPSHOT;
| 業務場景 | 推薦等級 | 理由 |
|---|---|---|
| 高並發 OLTP 核心交易(訂單、扣款) | READ COMMITTED / SNAPSHOT | 平衡一致性與並發,SNAPSHOT 避免鎖爭用 |
| 報表/分析查詢,可容忍髒資料 | READ UNCOMMITTED (NOLOCK) | 最高並發,無鎖負擔 |
| 需在同一交易多次讀取同一資料且必須一致 | REPEATABLE READ | 防止不可重複讀,較 SERIALIZABLE 輕量 |
| 財務結帳、庫存盤點等嚴格一致性 | SERIALIZABLE | 完全隔離,接受低並發 |
| 長交易讀取、高爭用熱點資料 | SNAPSHOT | 消除讀寫阻塞,需評估版本存放區成本 |
NOLOCK / READ UNCOMMITTED 可能讀到「半寫入」資料頁(中斷的更新),極少見但理論存在。