Skip to main content

16. Transactions - ACID

Mục tiêu bài học: Giới thiệu về Transactions trong SQL, cách sử dụng và đảm bảo tính nhất quán dữ liệu với ACID.

1️⃣ Transactions là gì?

Transaction (Giao dịch) trong SQL là một tập hợp các lệnh SQL được thực hiện như một đơn vị công việc.

  • Nếu tất cả lệnh thành công, thay đổi sẽ được lưu (COMMIT).
  • Nếu có lỗi xảy ra, tất cả thay đổi sẽ bị hủy (ROLLBACK).

💡 Ví dụ thực tế:

  • Chuyển tiền giữa 2 tài khoản (rút tiền từ A, cộng tiền vào B).
  • Đặt vé máy bay (trừ chỗ trống, tạo booking, cập nhật lịch trình).
  • Đặt hàng (trừ kho, tạo đơn, ghi lịch sử giao dịch).

2️⃣ Tính chất ACID của Transactions

Transactions phải tuân thủ ACID để đảm bảo tính toàn vẹn dữ liệu.

Tính chấtÝ nghĩa
Atomicity (Tính nguyên tử)Toàn bộ transaction thành công hoặc thất bại hoàn toàn.
Consistency (Tính nhất quán)Database không rơi vào trạng thái lỗi dù có lỗi xảy ra.
Isolation (Tính độc lập)Transactions chạy song song không làm ảnh hưởng lẫn nhau.
Durability (Tính bền vững)Sau khi COMMIT, dữ liệu sẽ được lưu vĩnh viễn.

💡 Ví dụ minh họa:

  • Nếu bạn rút 500K từ ATM nhưng máy bị lỗi sau khi trừ tiền tài khoản, hệ thống phải ROLLBACK để bạn không mất tiền.

3️⃣ Cách sử dụng Transactions trong SQL

🔹 Lệnh cơ bản

BEGIN;  -- Bắt đầu transaction
UPDATE accounts SET balance = balance - 500 WHERE id = 1; -- Trừ tiền tài khoản A
UPDATE accounts SET balance = balance + 500 WHERE id = 2; -- Cộng tiền tài khoản B
COMMIT; -- Xác nhận giao dịch

👉 Nếu tất cả lệnh thành công, COMMIT sẽ lưu thay đổi vĩnh viễn.

🔹 Xử lý lỗi với ROLLBACK

BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;

-- Giả sử có lỗi xảy ra khi cộng tiền vào tài khoản B
UPDATE accounts SET balance = balance + 500 WHERE id = 99999; -- ID không tồn tại!

ROLLBACK; -- Hủy toàn bộ giao dịch nếu có lỗi

👉 Nếu có lỗi, ROLLBACK sẽ khôi phục dữ liệu về trạng thái ban đầu.


4️⃣ Mô phỏng giao dịch ngân hàng 🏦

📌 Bảng accounts

CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
balance DECIMAL(10,2) NOT NULL
);

🔹 Thêm dữ liệu mẫu

INSERT INTO accounts (name, balance) VALUES ('Alice', 1000), ('Bob', 500);

🔹 Mô phỏng chuyển 200 từ Alice → Bob

BEGIN;

UPDATE accounts SET balance = balance - 200 WHERE name = 'Alice';

UPDATE accounts SET balance = balance + 200 WHERE name = 'Bob';

COMMIT;

👉 Nếu mọi thứ đúng, COMMIT sẽ lưu thay đổi.
👉 Nếu có lỗi (ví dụ: tài khoản không tồn tại), chúng ta cần ROLLBACK.

🔹 Kiểm tra kết quả

SELECT * FROM accounts;

5️⃣ Kiểm soát mức độ Isolation trong Transactions

SQL hỗ trợ nhiều mức độ Isolation để kiểm soát độ an toàn của Transactions.

Mức IsolationNguy cơ lỗi
READ UNCOMMITTEDCó thể đọc dữ liệu chưa COMMIT (không an toàn).
READ COMMITTEDChỉ đọc dữ liệu đã COMMIT (mặc định trong nhiều hệ quản trị CSDL).
REPEATABLE READCùng một SELECT trong transaction luôn trả về cùng một kết quả.
SERIALIZABLECực kỳ chặt chẽ, ngăn mọi transaction khác can thiệp.

Ví dụ:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
-- Các câu lệnh SQL ở mức Isolation cao nhất
COMMIT;

6️⃣ Bài tập thực hành 🎯

✅ Bài 1: Chuyển tiền giữa hai tài khoản

Viết transaction chuyển 300 từ Bob → Alice. Nếu tài khoản không đủ tiền, ROLLBACK.

💡 Gợi ý lời giải:

  • Kiểm tra số dư trước khi trừ tiền.
  • Nếu số dư không đủ, gọi ROLLBACK.
  • Nếu hợp lệ, cập nhật số dư và COMMIT.
BEGIN;
-- Kiểm tra số dư
SELECT balance INTO @bob_balance FROM accounts WHERE name = 'Bob';

IF @bob_balance < 300 THEN
ROLLBACK;
ELSE
UPDATE accounts SET balance = balance - 300 WHERE name = 'Bob';
UPDATE accounts SET balance = balance + 300 WHERE name = 'Alice';
COMMIT;
END IF;

✅ Bài 2: Mô phỏng đặt hàng

Giả sử chúng ta có bảng products (id, name, stock)orders (id, product_id, quantity).
Viết transaction để:

  • Trừ stock của sản phẩm.
  • Tạo bản ghi trong bảng orders.
  • Nếu có lỗi, ROLLBACK.

💡 Gợi ý lời giải:

BEGIN;

-- Kiểm tra sản phẩm còn hàng không
SELECT stock INTO @stock FROM products WHERE id = 1;

IF @stock < 1 THEN
ROLLBACK;
ELSE
-- Trừ stock
UPDATE products SET stock = stock - 1 WHERE id = 1;

-- Tạo đơn hàng
INSERT INTO orders (product_id, quantity) VALUES (1, 1);

COMMIT;
END IF;

✅ Bài 3: Kiểm tra hiệu suất Transaction

Dùng EXPLAIN ANALYZE để kiểm tra hiệu suất truy vấn khi dùng transaction.

💡 Gợi ý lời giải:

EXPLAIN ANALYZE 
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
COMMIT;

👉 Kết quả giúp xác định có cần thêm INDEX để tối ưu không.


🎯 Tóm tắt bài học Ngày 16

Transactions giúp đảm bảo tất cả các lệnh thành công hoặc bị hủy toàn bộ.
ACID đảm bảo dữ liệu không bị lỗi khi có nhiều giao dịch đồng thời.
✅ Dùng COMMIT để lưu, ROLLBACK để hủy nếu có lỗi.
Thực hành: Chuyển tiền, đặt hàng, kiểm soát mức độ Isolation.


🚀 Tiếp theo: Stored Procedures & Functions.

📌 Lộ trình: Học SQL trong 30 ngày.