SQL & Database/SQL nâng cao/Transaction & ACID
3/3
~16 phútSQL nâng cao

Transaction & ACID

Hiểu transaction, ACID properties, isolation levels và cách xử lý concurrent access trong database.

Transaction là gì?

Transaction là một nhóm thao tác được thực hiện như một đơn vị: hoặc tất cả thành công, hoặc tất cả rollback.

Ví dụ chuyển tiền:

BEGIN TRANSACTION;

UPDATE accounts SET balance = balance - 1000000 WHERE id = 1;  -- Trừ tiền Alice
UPDATE accounts SET balance = balance + 1000000 WHERE id = 2;  -- Cộng tiền Bob

COMMIT;  -- Xác nhận cả 2 thao tác

Nếu bước 2 lỗi, bước 1 cũng bị rollback — Alice không mất tiền mà Bob không nhận được.

ACID Properties

PropertyÝ nghĩaVí dụ
AtomicityTất cả hoặc không gìChuyển tiền: trừ + cộng phải cùng thành công
ConsistencyDữ liệu luôn hợp lệBalance không bao giờ âm
IsolationTransaction không ảnh hưởng lẫn nhau2 người chuyển tiền cùng lúc
DurabilitySau COMMIT, dữ liệu không mấtMất điện sau COMMIT vẫn giữ data

Isolation Levels

Đây là phần khó nhất của transaction — cân bằng giữa correctnessperformance:

READ UNCOMMITTED  →  Nhanh nhất, ít an toàn nhất
READ COMMITTED    →  Default của PostgreSQL
REPEATABLE READ   →  Default của MySQL
SERIALIZABLE      →  Chậm nhất, an toàn nhất

Các vấn đề khi thiếu isolation

Dirty Read — Đọc dữ liệu chưa commit:

-- Transaction A                    -- Transaction B
UPDATE products SET price = 100;
                                    SELECT price FROM products;  -- Thấy 100
ROLLBACK;                           -- Nhưng 100 không tồn tại!

Non-Repeatable Read — Đọc 2 lần ra kết quả khác:

-- Transaction A                    -- Transaction B
SELECT price FROM products;  -- 50
                                    UPDATE products SET price = 100;
                                    COMMIT;
SELECT price FROM products;  -- 100 (khác lần trước!)

Phantom Read — Số lượng row thay đổi:

-- Transaction A                    -- Transaction B
SELECT COUNT(*) FROM orders;  -- 10
                                    INSERT INTO orders VALUES (...);
                                    COMMIT;
SELECT COUNT(*) FROM orders;  -- 11 (có row mới!)

ℹ️ Chọn Isolation Level nào?

  • READ COMMITTED (default PostgreSQL): Đủ cho hầu hết ứng dụng web
  • REPEATABLE READ: Khi cần đọc nhất quán trong transaction (báo cáo)
  • SERIALIZABLE: Khi business logic yêu cầu tuyệt đối chính xác (tài chính)

Deadlock

Khi 2 transaction chờ nhau mãi mãi:

-- Transaction A                    -- Transaction B
UPDATE accounts SET ... WHERE id=1; -- Lock row 1
                                    UPDATE accounts SET ... WHERE id=2; -- Lock row 2
UPDATE accounts SET ... WHERE id=2; -- Chờ row 2 (B đang giữ)
                                    UPDATE accounts SET ... WHERE id=1; -- Chờ row 1 (A đang giữ)
-- DEADLOCK!

Cách tránh: Luôn lock theo thứ tự cố định (id nhỏ trước).

Best Practices

  1. Transaction ngắn nhất có thể — giữ lock ít thời gian
  2. Không gọi API bên ngoài trong transaction — nếu API chậm, lock bị giữ lâu
  3. Chọn isolation level phù hợp — không dùng SERIALIZABLE khi không cần
  4. Retry khi deadlock — database tự detect và kill 1 transaction