場景:兩用戶同時新增資料,程式邏輯:
1. `BEGIN TRAN` → 2. `INSERT INTO TableA ...` → 3. `SELECT COUNT(*) FROM TableA WHERE ...` 檢查唯一性 → 4. `COMMIT/ROLLBACK`
| 方案 | 核心機制 | 優點 | 缺點/風險 |
|---|---|---|---|
| 1. 降低隔離等級 READ UNCOMMITTED |
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED (或 WITH (NOLOCK))SELECT 讀取未認可資料 (Dirty Read),不請求 S 鎖。 |
零封鎖、效能最佳、程式碼改動最小。 | 讀到臟資料 (對方可能 ROLLBACK);唯一性檢查失效 (讀不到對方剛 INSERT 尚未認可的列)。不適合業務關鍵驗證。 |
| 2. 表層鎖提示 TABLOCK / TABLOCKX |
INSERT INTO TableA WITH (TABLOCK) ...INSERT 直接請求 表級 X 鎖 (或 S 鎖),序列化所有存取。 |
完全避免死鎖、邏輯正確 (可讀到對方認可前的資料若配合 HOLDLOCK)。 | 並發度極低,大表 INSERT 期間全表封鎖,嚴重影響吞吐量。僅適用小表/低併發。 |
| 3. 應用層鎖 / 虛設資源鎖 sp_getapplock |
邏輯上序列化「檢查並插入」關鍵區:EXEC sp_getapplock @Resource='TableA_Insert', @LockMode='Exclusive', @LockOwner='Transaction';... INSERT + SELECT ... EXEC sp_releaseapplock @Resource='TableA_Insert', @LockOwner='Transaction'; |
粒度可控 (不鎖全表)、不影響其他無關查詢、支援逾時控制、跨程式協調。 | 需修改程式碼包裝關鍵區;開發者需理解應用鎖語意;若交易長仍阻塞後續請求。 |
UNIQUE CONSTRAINT 或 UNIQUE INDEX。移除應用層 `SELECT COUNT(*)` 檢查,直接 `INSERT` 捕捉錯誤 2627/2601 回滾。此為根治方案,無鎖爭用、效能最佳、邏輯正確。