Study Web

Advanced SQL

Transaction là gì?

Hiểu về autocommit, nguy cơ khi không dùng transaction, cách dùng SET AUTOCOMMIT=FALSE, START TRANSACTION, COMMIT, và ROLLBACK để đảm bảo an toàn dữ liệu.

Transaction là gì?

Một transaction (giao dịch) là một đơn vị công việc gồm một hoặc nhiều lệnh SQL được thực hiện như một khối nguyên tử — hoặc tất cả thành công, hoặc tất cả được hoàn tác.

Transaction đảm bảo tính chất ACID:

  • Atomicity: Tất cả hoặc không có gì
  • Consistency: Database luôn ở trạng thái hợp lệ
  • Isolation: Transaction độc lập với nhau
  • Durability: Dữ liệu sau COMMIT tồn tại vĩnh viễn

1. Autocommit — Nguy cơ mặc định

MySQL mặc định bật autocommit = ON. Điều này có nghĩa mỗi câu DML (INSERT, UPDATE, DELETE) được tự động COMMIT ngay lập tức — không thể hoàn tác.

⚠️ Câu chuyện thực tế (Bài giảng Week 8)
Một developer chạy lệnh:
UPDATE Orders SET CustomerID = 999;
Quên WHERE clause → 45,364 dòng bị cập nhật sai ngay lập tức và không thể hoàn tác vì autocommit đang ON!
SHOW VARIABLES LIKE 'autocommit';

Kết quả thường là ON theo mặc định.

2. Tắt Autocommit — SET AUTOCOMMIT=FALSE

Cách 1: Tắt autocommit cho phiên làm việc hiện tại:

SET AUTOCOMMIT = FALSE;

UPDATE Orders SET CustomerID = 999 WHERE OrderID = 101;

SELECT * FROM Orders WHERE OrderID = 101;

ROLLBACK;

Với AUTOCOMMIT=FALSE, lệnh UPDATE chưa được lưu vĩnh viễn. Bạn có thể kiểm tra kết quả, rồi quyết định COMMIT hoặc ROLLBACK.

Quy trình an toàn với AUTOCOMMIT=FALSE

Workflow:
  1. SET AUTOCOMMIT = FALSE;
  2. Thực hiện các lệnh DML (INSERT, UPDATE, DELETE)
  3. SELECT để kiểm tra kết quả
  4. Nếu đúng → COMMIT;
  5. Nếu sai → ROLLBACK;

3. START TRANSACTION — Khối giao dịch rõ ràng

Cách tốt nhất để kiểm soát transaction — dùng START TRANSACTION ngay cả khi autocommit đang ON:

START TRANSACTION;

INSERT INTO Account (AccID, Balance) VALUES (101, 1000);
INSERT INTO Account (AccID, Balance) VALUES (102, 500);

UPDATE Account SET Balance = Balance - 200 WHERE AccID = 101;
UPDATE Account SET Balance = Balance + 200 WHERE AccID = 102;

SELECT * FROM Account;

COMMIT;

Ví dụ trên mô phỏng chuyển tiền ngân hàng: trừ 200 từ tài khoản 101 và cộng 200 vào tài khoản 102. Cả hai phải thành công, hoặc cả hai bị hoàn tác.

4. ROLLBACK — Hoàn tác

ROLLBACK hủy bỏ tất cả thay đổi từ khi bắt đầu transaction (hoặc từ khi SET AUTOCOMMIT=FALSE):

START TRANSACTION;

DELETE FROM Staff WHERE BranchID = 101;

SELECT COUNT(*) FROM Staff;

ROLLBACK;

SELECT COUNT(*) FROM Staff;

Sau ROLLBACK, số dòng trong Staff trở về giống như trước khi DELETE.

Khi nào dùng ROLLBACK?

  • Phát hiện lỗi trong dữ liệu sau khi chạy lệnh DML
  • Một trong các bước của transaction thất bại
  • Kiểm tra dữ liệu và thấy kết quả không như mong đợi

5. SAVEPOINT — Điểm lưu trữ trung gian

START TRANSACTION;

INSERT INTO Staff (StaffID, StaffName) VALUES (10, 'Anna');
SAVEPOINT after_insert;

UPDATE Staff SET BranchID = 999 WHERE StaffID = 10;

ROLLBACK TO SAVEPOINT after_insert;

COMMIT;

Dùng SAVEPOINT để ROLLBACK về một điểm giữa transaction, không phải về tận đầu.

6. Locking và Isolation

Khi nhiều transaction chạy song song, MySQL dùng locks để tránh xung đột. Mức độ isolation mặc định là REPEATABLE READ.

Vấn đề phổ biến với concurrent access:

  • Dirty Read: Đọc dữ liệu chưa COMMIT của transaction khác
  • Non-repeatable Read: Đọc 2 lần cùng dòng nhưng ra kết quả khác
  • Phantom Read: Query trả về số dòng khác nhau trong cùng transaction

InnoDB (storage engine mặc định của MySQL) hỗ trợ đầy đủ ACID và row-level locking.