Mức cô lập giao dịch (Transaction Isolation Level)
1. Tổng quan
A. Định nghĩa
Là mức quy định cho phép các giao dịch thực thi đồng thời ảnh hưởng lẫn nhau đến mức độ nào (mức độ cô lập). Nó hiện thực hóa trong thực tiễn tính cô lập (Isolation) của ACID, và là núm vặn điều chỉnh sự đánh đổi giữa tính đồng thời và tính nhất quán.
Lý tưởng nhất là mọi giao dịch phải được cô lập hoàn hảo như thể chỉ chạy một mình (Serializable), nhưng làm vậy thì thông lượng xử lý đồng thời giảm mạnh. Vì vậy, tiêu chuẩn (ANSI SQL) thay vì cô lập hoàn hảo đã định nghĩa nhiều bậc đổi lấy tính đồng thời bằng cái giá chấp nhận một số hiện tượng bất thường. Hiểu mức cô lập chính là đánh giá "cho phép hiện tượng bất thường nào và mua được hiệu năng nào".
B. Bối cảnh ra đời và sự cần thiết
Tăng cường cô lập thì tính nhất quán tăng nhưng tranh chấp khóa tăng làm tính đồng thời giảm; nới lỏng thì tính đồng thời tăng nhưng rủi ro hiện tượng bất thường lớn hơn. Tức là tồn tại quan hệ tỷ lệ nghịch cô lập↑ = nhất quán↑·đồng thời↓. Nếu áp đặt mức cô lập cao nhất cho mọi nghiệp vụ thì không đạt được hiệu năng, ngược lại nếu dùng mức cô lập thấp một cách tùy tiện thì tính toàn vẹn dữ liệu bị phá vỡ. Vì vậy, cần lựa chọn mức phù hợp theo tính chất nghiệp vụ — là giao dịch tiền bạc nên tính toàn vẹn là tuyệt đối, hay là truy vấn thống kê nên có thể chấp nhận một chút thiếu chính xác.
2. Hiện tượng bất thường theo mức cô lập
Các mức cô lập tạo thành bậc thang theo cách chặn lần lượt từng hiện tượng bất thường từ mức thấp trong ba hiện tượng tiêu biểu. Càng xuống dưới càng chặn được nhiều hiện tượng bất thường hơn nhưng tính đồng thời giảm.
| Mức cô lập | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| Read Uncommitted | Xảy ra | Xảy ra | Xảy ra |
| Read Committed | Ngăn chặn | Xảy ra | Xảy ra |
| Repeatable Read | Ngăn chặn | Ngăn chặn | Xảy ra (có thể) |
| Serializable | Ngăn chặn | Ngăn chặn | Ngăn chặn |
flowchart LR
A[Read Uncommitted<br/>Cô lập thấp nhất] --> B[Read Committed] --> C[Repeatable Read] --> D[Serializable<br/>Cô lập cao nhất]
3. Ví dụ về các hiện tượng bất thường
Ba hiện tượng bất thường được phân biệt lần lượt bởi "có đọc dữ liệu chưa xác nhận không / đọc cùng một thứ hai lần thì giá trị có thay đổi không / số lượng bản ghi có thay đổi không". Nhìn qua ví dụ thì nguyên lý trở nên rõ ràng.
Dirty Read (đọc bẩn) là đọc thay đổi chưa được commit. B truy vấn số dư là 200 trong khi A sửa số dư từ 100→200 (chưa commit), sau đó A rollback thì B đã đọc một giá trị chưa từng tồn tại. Từ Read Committed trở lên chỉ đọc dữ liệu đã commit nên ngăn được hiện tượng này.
Non-repeatable Read (đọc không lặp lại được) là trong một giao dịch, đọc cùng một dòng hai lần nhưng giá trị khác nhau. Nếu giữa lúc B đọc một dòng và đọc lại, A thay đổi·commit dòng đó, thì B nhận câu trả lời khác cho cùng một truy vấn. Repeatable Read duy trì snapshot của các dòng đã đọc trong suốt giao dịch để ngăn hiện tượng này.
Phantom Read (đọc bóng ma) là số lượng bản ghi của truy vấn theo phạm vi thay đổi. Nếu giữa lúc B truy vấn "các tài khoản có số dư từ 100 trở lên" và truy vấn lại, A chèn·commit một dòng mới thỏa điều kiện, thì một dòng trước đó không có sẽ xuất hiện. Vì hiện tượng này liên quan đến phạm vi chứ không phải từng dòng riêng lẻ, nó chỉ bị chặn hoàn toàn ở Serializable (hoặc khóa phạm vi/Next-key Lock).
| Mức | Ví dụ |
|---|---|
| Read Uncommitted | A sửa số dư 100→200 chưa commit, B truy vấn được 200 → khi A rollback thì Dirty Read |
| Read Committed | Trong lúc B truy vấn, A thay đổi·commit → truy vấn lại thì giá trị khác (Non-repeatable) |
| Repeatable Read | Cùng dòng thì nhất quán nhưng khi có dòng mới được chèn trong lúc truy vấn phạm vi thì Phantom |
| Serializable | Tuần tự hóa hoàn toàn, ngăn mọi hiện tượng bất thường, tính đồng thời thấp nhất |
4. Kỹ thuật điều khiển tương tranh
Mức cô lập có hiệu năng khác nhau rất nhiều tùy theo cách hiện thực. Phương thức dựa trên Lock truyền thống đặt khóa chia sẻ·khóa độc quyền cho đọc·ghi và bảo đảm tính tuần tự bằng khóa hai pha (2PL), nhưng đọc chặn ghi nên tranh chấp lớn. Để vượt qua giới hạn này, các DBMS hiện đại sử dụng MVCC (điều khiển tương tranh đa phiên bản).
| Kỹ thuật | Nội dung |
|---|---|
| Dựa trên Lock | Khóa chia sẻ·độc quyền, 2PL (khóa hai pha) |
| MVCC | Tối thiểu hóa xung đột đọc-ghi bằng phiên bản snapshot (Oracle·PostgreSQL) |
| Snapshot Isolation | Đọc snapshot tại thời điểm bắt đầu giao dịch để bảo đảm tính nhất quán |
MVCC quan trọng vì nó không ghi đè dữ liệu mà duy trì nhiều phiên bản, để phía đọc xem snapshot tại thời điểm của mình còn phía ghi tạo phiên bản mới, qua đó đạt được "đọc không chặn ghi (readers don't block writers)". Nhờ đó có thể đồng thời đạt được tính nhất quán cao và tính đồng thời cao.
5. Lưu ý và hàm ý
Điểm cần chú ý trong thực tiễn là mỗi DBMS có giá trị mặc định và hành vi thực tế khác nhau. Mặc định của Oracle·PostgreSQL là Read Committed, còn MySQL InnoDB là Repeatable Read; đặc biệt InnoDB dùng Next-key Lock nên ngay cả ở Repeatable Read cũng chặn được phần lớn Phantom. Vì vậy, không nên chỉ tin vào bảng lý thuyết của tiêu chuẩn mà phải xác nhận hiện thực thực tế của engine đang dùng. Chiến lược lựa chọn rất rõ ràng. Nếu tính toàn vẹn là tuyệt đối như thanh toán tài chính thì dùng Serializable (hoặc khóa tường minh), còn nếu chủ yếu là truy vấn·thống kê thì dùng mức thấp để phát huy tính đồng thời. Khi đã hạ mức cô lập, việc bổ sung tính toàn vẹn ở cấp ứng dụng bằng khóa lạc quan (kiểm tra cột phiên bản) để cân bằng hiệu năng và tính nhất quán là đánh giá mang tính Kỹ sư chuyên nghiệp (Professional Engineer).
Tóm tắt một câu: Mức cô lập càng đi từ Read Uncommitted→Committed→Repeatable Read→Serializable thì càng lần lượt chặn Dirty·Non-repeatable·Phantom Read nhưng hy sinh tính đồng thời; nó được hiện thực bằng Lock·MVCC, và cần chọn mức phù hợp với yêu cầu toàn vẹn của nghiệp vụ để cân bằng giữa tính nhất quán và hiệu năng.