Trong khoá học này tụi mình sẽ nói về transaction tới ba lần lận. Mỗi lần lại phát hiện thêm điều mới. Giờ mình sẽ học mấy thứ cơ bản về transaction trước đã. Nửa sau khoá học sẽ tìm hiểu về isolation level của transaction, còn cuối cùng thì sẽ là mấy chi tiết về nested transaction.
Transaction là gì
Bắt đầu từ cái dễ nhất — định nghĩa. Transaction là một nhóm thao tác mà chỉ thực hiện cùng nhau thôi. Hết.
Từ đó rút ra một điều quan trọng: nếu bất kỳ thao tác nào trong nhóm bị lỗi, thì phải rollback kết quả của tất cả thao tác còn lại và trả hệ thống về trạng thái ban đầu.
Với góc nhìn SQL, transaction là một tập các thao tác (ví dụ như insert, update hoặc delete dữ liệu), đảm bảo rằng hoặc tất cả các thao tác trong transaction đều thành công, hoặc không có thao tác nào được thực hiện cả. Kiểu này giúp làm việc với database cực kỳ đáng tin cậy và nhất quán, nhất là trong mấy tình huống quan trọng như xử lý thanh toán hoặc cập nhật dữ liệu liên quan.
Ví dụ, bạn chuyển tiền giữa hai tài khoản ngân hàng. Nếu đơn giản hoá, sẽ có hai bước liên tiếp:
- Trừ tiền từ một tài khoản.
- Cộng đúng số tiền đó vào tài khoản khác.
Nếu bị lỗi ở cuối cùng (kiểu như server sập), quan trọng là không ai bị thiệt cả. Nói cách khác, hoặc cả hai bước đều thành công (transaction được commit), hoặc cả hai bước đều bị rollback (transaction bị huỷ).
Transaction và nguyên tắc ACID
Transaction dựa trên nguyên tắc ACID, nhắc ta về bốn đặc điểm chính:
- Atomicity (Tính nguyên tử): tất cả hoặc không gì cả. Hoặc mọi thao tác trong transaction đều thực hiện, hoặc đều bị rollback.
- Consistency (Tính nhất quán): dữ liệu luôn ở trạng thái hợp lệ trước và sau transaction.
- Isolation (Tính cô lập): mỗi transaction hoạt động như thể nó là duy nhất trong hệ thống.
- Durability (Tính bền vững): sau khi commit, dữ liệu sẽ được lưu lại, kể cả khi server sập.
Các lệnh cơ bản để quản lý transaction
Giờ chuẩn bị thực hành nhé! Đây là ba lệnh chính để quản lý transaction:
BEGIN
Bắt đầu một transaction mới. Tất cả thao tác sau đó sẽ nằm trong transaction này.COMMIT
Ghi nhận thay đổi. Sau khi chạy lệnh này, mọi thao tác sẽ được lưu lại vĩnh viễn.ROLLBACK
Huỷ thay đổi. Nếu có gì sai, có thể rollback transaction, dữ liệu sẽ quay về trạng thái ban đầu.
Cú pháp cơ bản của transaction
Cấu trúc đơn giản của một transaction:
BEGIN;
-- đây là chỗ bạn viết các thao tác SQL của mình
COMMIT;
Ví dụ dùng ROLLBACK:
BEGIN;
-- thay đổi bảng students
UPDATE students
SET grade = grade + 10
WHERE id = 1;
-- Ồ! Nhận ra đây là lỗi rồi.
ROLLBACK;
Ví dụ dùng transaction trong bài toán thực tế
Giả sử mình có các bảng sau:
students:
| id | name | grade |
|---|---|---|
| 1 | Otto Lin | 85 |
| 2 | Anna Song | 90 |
courses:
| course_id | course_name |
|---|---|
| 1 | Toán học |
| 2 | Lịch sử |
Giả sử mình muốn vừa đăng ký khoá học cho sinh viên, vừa cập nhật điểm trung bình của bạn ấy cùng lúc:
BEGIN;
-- Bước 1: Thêm bản ghi vào bảng "đăng ký khoá học"
INSERT INTO course_enrollments (student_id, course_id)
VALUES (1, 2);
-- Bước 2: Cập nhật điểm trung bình của sinh viên
UPDATE students
SET grade = grade + 5
WHERE id = 1;
COMMIT;
Nếu server sập giữa hai bước thì sao? Nếu không dùng transaction, dữ liệu sẽ bị lệch: đăng ký khoá học đã thêm, nhưng điểm trung bình chưa cập nhật. Nhưng với transaction, hoặc cả hai thao tác đều thành công, hoặc cả hai đều bị huỷ.
Xử lý lỗi trong transaction
Đôi khi có gì đó không ổn, mình cần xử lý lỗi cho chuẩn. Trong PostgreSQL, nếu có lỗi thì transaction sẽ tự động rollback.
Giờ thử cố tình gây lỗi xem sao nhé. Giả sử cột student_id trong bảng course_enrollments có ràng buộc unique. Thử thêm dòng trùng lặp xem:
BEGIN;
INSERT INTO course_enrollments (student_id, course_id)
VALUES (1, 2);
-- KẾT THÚC TRANSACTION (chưa thực hiện)
COMMIT;
Nếu thêm sinh viên đã đăng ký khoá học rồi, sẽ bị lỗi, và PostgreSQL sẽ tự động rollback transaction.
Dùng ROLLBACK để tự rollback bằng tay
Nhiều khi không đoán trước được lỗi, bạn sẽ muốn rollback transaction nếu có gì không ổn:
BEGIN;
-- Thêm sinh viên mới
INSERT INTO students (name, grade)
VALUES ('Omori Sanny', 75);
-- Ối! Nhận ra thêm sinh viên này nhầm rồi.
ROLLBACK;
Sau lệnh ROLLBACK bảng vẫn y nguyên — Omori Sanny không xuất hiện trong students.
Mẹo hữu ích và lỗi thường gặp
Làm việc với transaction sẽ dễ hơn nếu nhớ mấy quy tắc sau:
- Luôn dùng transaction nếu thao tác của bạn có nhiều bước, nhất là khi sửa dữ liệu ở nhiều bảng.
- Đừng quên commit thay đổi (
COMMIT). Nếu không, transaction sẽ chưa hoàn thành, dữ liệu sẽ không đổi. - Bọc các thao tác phức tạp vào transaction để giữ dữ liệu nhất quán.
- Nếu thấy lỗi ở bất kỳ bước nào, đừng ngại dùng
ROLLBACK.
Giờ bạn đã biết cách kiểm soát thao tác với transaction rồi, tới lúc áp dụng thực tế và học tiếp về transaction để đảm bảo tính toàn vẹn dữ liệu nhé!
GO TO FULL VERSION