Transaction Isolation Level - REPEATABLE READ
Dạo quanh với REPEATABLE READ – cái thằng đọc lì như trâu, đọc cái gì là cố giữ đúng y chang tới cùng.
Vô chuyện!
1. REPEATABLE READ là gì?
REPEATABLE READ có nghĩa là:
Khi một transaction đọc một dữ liệu, thì trong suốt cái transaction đó, đọc lại cũng phải thấy y như cũ.
Không ai được phép update hay delete cái dữ liệu mình đã đọc trong lúc mình đang làm việc.
→ Đọc lần 1 thế nào → Đọc lần 2 cũng thế → Không đổi.
Tuy nhiên:
- Cái gì mình chưa đọc tới (ví dụ thêm dòng mới) thì vẫn có thể mọc ra, nên Phantom Read vẫn có thể xảy ra.
2. Vậy REPEATABLE READ bảo vệ được những gì?
| Hiện tượng | Có xảy ra ở REPEATABLE READ? |
| Dirty Read | Không |
| Non-repeatable Read | Không |
| Phantom Read | Có thể (dữ liệu mới mọc ra thêm dòng) |
3. Một số tình huống
Bối cảnh:
Tôi kiểm tra giá món hàng trong kho.
Query 1:
SELECT price FROM product WHERE id = 555;Trong lúc tôi đang ngủ gật, thằng sale kia định tăng giá và commit.
→ Nhưng nếu cấu hình ở level REPEATABLE READ, thì:
Nó không cập nhật được đâu.
Nó phải chờ tui commit hoặc rollback xong nó mới làm được.
Diễn giải:
→ Dữ liệu tui đã đọc thì khóa cứng luôn.
→ Người khác chỉ biết ngồi ngáp chờ tui xong.
Kết quả:
Đọc 1 lần hay 10 lần, giá vẫn như ban đầu.
An toàn, chắc cú.
4. Một lưu ý cần nhớ
REPEATABLE READ giữ giá trị rất chặt, nhưng không bảo vệ hoàn toàn việc mọc thêm dòng (Phantom Read).
MySQL (InnoDB) xử lý Phantom Read luôn, nhưng chuẩn SQL thì REPEATABLE READ vẫn dính Phantom Read.
Nếu cần đọc mà giữ nguyên mọi thứ mình thấy lần đầu, không cho phép thay đổi gì cả, thì REPEATABLE READ là một chọn khá chuẩn.
Nhưng nhớ, vì nó khóa lâu hơn, nên: → Dễ bị deadlock (khoá cứng dữ liệu làm nhau kẹt cứng).
→ Phải xài cẩn thận với mấy transaction kéo dài lê thê.
5. Ví dụ demo SQL cho chắc tay
-- Session 1
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
SELECT price FROM product WHERE id = 555;
-- Đọc xong, để nguyên session này.
-- Session 2
BEGIN TRANSACTION;
UPDATE product SET price = price + 10 WHERE id = 555;
-- Session 2 sẽ bị kẹt, chờ Session 1 commit hoặc rollback!
-- Quay lại Session 1
COMMIT;
-- Giờ Session 2 mới được chạy.
Kết quả:
Trong suốt transaction của Session 1, giá sản phẩm y chang dù thằng khác rình mò update.
Session 2 bị khóa chờ.
6. Nâng cao
Trong REPEATABLE READ, cái gọi là Phantom Read chỉ xảy ra khi CÓ THÊM bản ghi mới thỏa điều kiện query thôi, không phải khi bản ghi bị bớt đi.
Giải thích kỹ hơn chút:
| Hành động | Có phải Phantom Read không? |
| Thêm bản ghi mới (insert) vào và nó thỏa điều kiện query ban đầu | Có Phantom Read |
| Xóa bản ghi (delete) làm nó biến mất khỏi kết quả query ban đầu | Không Phantom Read |
| Update bản ghi làm nó mới thỏa điều kiện query ban đầu | Có Phantom Read |
Tại sao xóa bản ghi lại không gọi là Phantom Read?
Vì bản chất Phantom Read là:
"Đọc lần 1, thấy 5 bản ghi. Đọc lần 2, lại thấy 6 bản ghi (có thêm 1 bản ghi mới thỏa điều kiện mà hồi nãy không có)."
Mục tiêu của Repeatable Read là cố gắng giữ cho dữ liệu thấy lúc đầu "cố định" trong cả transaction.
Nếu bản ghi bị mất đi thì lần sau SELECT vẫn chỉ đọc snapshot cũ (nó giữ nguyên theo Isolation của transaction).
Nếu bản ghi mới chèn vào, bản ghi này không nằm trong snapshot cũ → mà lại thỏa điều kiện query, thì mới lòi ra cái gọi là Phantom.
7. Tổng kết
| Đặc điểm | Nội dung |
| Bảo vệ khỏi Dirty Read | Có |
| Bảo vệ khỏi Non-repeatable Read | Có |
| Bảo vệ khỏi Phantom Read | Có thể, tuỳ DBMS |
| Ứng dụng thích hợp | Giao dịch yêu cầu cực kỳ ổn định dữ liệu, như ngân hàng, ví điện tử, e-commerce |
Nếu muốn đọc một lần và yên tâm rằng không ai sửa phá gì được tới lúc mình xong việc, thì REPEATABLE READ là bạn chí cốt. Chỉ cần nhớ là, đừng giữ khóa lâu quá, không thì chết kẹt chung với thiên hạ đó.