# SQL Server Isolation Levels & Concurrency

Hai request cùng đọc `Stock = 1`. Cả hai cùng thấy còn hàng và cùng redeem thành công. Đây không còn là validation problem đơn thuần mà là **concurrency problem**.

## Dirty Read

Transaction A cập nhật nhưng chưa commit:

“`text
Balance = 1000
Update -> 500
Not committed
“`

Transaction B đọc được `500`.

Sau đó A rollback về `1000`.

B đã đọc dữ liệu chưa từng thực sự được commit.

## Non-repeatable Read

Transaction A:

“`sql
SELECT Balance
FROM Accounts
WHERE Id = 1;
— 1000
“`

Transaction B:

“`sql
UPDATE Accounts
SET Balance = 500
WHERE Id = 1;

COMMIT;
“`

Transaction A đọc lại và nhận `500`.

## Phantom Read

Transaction A:

“`sql
SELECT *
FROM Orders
WHERE Amount > 1000;
“`

Lần đầu có 10 rows. Transaction B insert thêm một row phù hợp điều kiện. A query lại thấy 11 rows.

## Lost Update

Hai request cùng đọc:

“`text
Stock = 10
“`

A tính `9`, B cũng tính `9`, rồi cả hai ghi `9`.

Kết quả đúng đáng lẽ phải là `8`.

## Isolation Levels

### READ UNCOMMITTED

“`sql
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
“`

Cho phép đọc uncommitted data.

`NOLOCK` thường có behavior tương tự:

“`sql
SELECT *
FROM Orders WITH (NOLOCK);
“`

`NOLOCK` không phải performance miễn phí. Bạn đánh đổi consistency để giảm locking.

### READ COMMITTED

Là isolation level mặc định phổ biến của SQL Server.

Ngăn dirty read nhưng vẫn có thể gặp non-repeatable read và phantom read.

### REPEATABLE READ

Giữ shared lock lâu hơn để ngăn row đã đọc bị thay đổi trong transaction.

Trade-off là blocking cao hơn.

### SERIALIZABLE

Mạnh nhất theo locking-based model.

Ngăn:

– Dirty Read
– Non-repeatable Read
– Phantom Read

Nhưng đổi lại có thể tăng blocking, giảm throughput và tăng deadlock risk.

### SNAPSHOT

Snapshot sử dụng row versioning.

Reader có thể đọc một version phù hợp thay vì phải chờ writer release lock.

“`text
Version 1 -> Balance = 100
Version 2 -> Balance = 80
“`

Transaction bắt đầu trước Version 2 có thể tiếp tục nhìn thấy Version 1.

## READ_COMMITTED_SNAPSHOT

“`sql
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON;
“`

Khi bật:

– `READ COMMITTED` dùng row versioning cho reads
– giảm reader/writer blocking
– tăng concurrency

Trade-off là version-store overhead và read semantics thay đổi.

## ALLOW_SNAPSHOT_ISOLATION

“`sql
ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON;
“`

Application sau đó có thể dùng:

“`sql
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
“`

Khác biệt cần nhớ:

“`text
READ_COMMITTED_SNAPSHOT
-> thay behavior của READ COMMITTED

ALLOW_SNAPSHOT_ISOLATION
-> cho phép transaction explicitly dùng SNAPSHOT
“`

## Interview questions

### What is SQL Server’s default isolation level?

> Read Committed is the traditional default isolation level in SQL Server.

### Why not use Serializable everywhere?

> Because stronger isolation reduces concurrency and increases locking, blocking, and deadlock risk. The isolation level should match the business consistency requirement.

## Key takeaways

Isolation level không phải càng cao càng tốt. Nó là trade-off giữa:

“`text
Consistency
vs
Concurrency
vs
Performance
“`

**Next:** Part 3 — Locking, Blocking & Deadlocks