Hãy tưởng tượng bạn đang viết một cuốn sách. Nhưng mà, không phải lúc nào mọi thứ cũng suôn sẻ đâu. Đôi khi bạn viết xong cả một chương, nhưng khi đọc lại thì thấy đoạn thứ 5 dở tệ. Bạn sẽ làm gì? Bạn đâu có vứt cả chương đó vào thùng rác đúng không? Thay vào đó, bạn chỉ sửa những chỗ mà bạn thấy chưa ổn thôi.
SAVEPOINT trong PostgreSQL cũng hoạt động kiểu như vậy đó. Nó cho phép bạn:
- Tạo điểm lưu bên trong giao dịch — giống như đánh dấu trang trong sách vậy.
- Quay lại các điểm đó để huỷ một phần thao tác đã làm, mà không cần rollback toàn bộ giao dịch.
- Tiếp tục làm việc với dữ liệu còn lại mà không phải bắt đầu lại từ đầu.
Cú pháp cơ bản của SAVEPOINT
Các lệnh liên quan đến SAVEPOINT khá là đơn giản. Đây là bộ lệnh cơ bản:
Tạo điểm lưu (SAVEPOINT):
SAVEPOINT savepoint_name;
Nó giống như bạn nói: "Đánh dấu chỗ này lại, biết đâu lát nữa cần quay lại."
Rollback về điểm lưu đã tạo (ROLLBACK TO SAVEPOINT):
ROLLBACK TO SAVEPOINT savepoint_name;
Nếu có gì đó không ổn, bạn quay lại SAVEPOINT đã chỉ định và huỷ mọi thay đổi kể từ lúc tạo nó.
RELEASE SAVEPOINT):
RELEASE SAVEPOINT savepoint_name;
Lệnh này sẽ giải phóng chỗ đã "đánh dấu". Sau đó bạn sẽ không thể rollback về điểm đó nữa.
Ví dụ đơn giản: mua hàng trong shop online
Giả sử bạn đang quản lý một shop online. Khách hàng thêm vài món vào giỏ, và bạn muốn thực hiện một giao dịch gồm đặt hàng và cập nhật tồn kho. Nhưng nếu một bước nào đó fail, bạn chỉ muốn huỷ một phần giao dịch, chứ không phải tất cả.
BEGIN;
-- Bước 1: Đặt trước sản phẩm "Sách SQL"
UPDATE inventory SET stock = stock - 1 WHERE product_id = 101;
-- Tạo điểm lưu
SAVEPOINT book_reserved;
-- Bước 2: Đặt trước sản phẩm "Cốc PostgreSQL"
UPDATE inventory SET stock = stock - 1 WHERE product_id = 102;
-- Ôi không, phát hiện ra kho hết cốc rồi!
ROLLBACK TO SAVEPOINT book_reserved;
-- Chỉ xác nhận thay đổi cho sách thôi
COMMIT;
Chuyện gì xảy ra trong ví dụ này?
- Bắt đầu giao dịch với
BEGIN. - Sau khi đặt trước sách, tạo điểm lưu
book_reserved. Đây là "checkpoint" đầu tiên. - Thử đặt trước cốc, nhưng bị lỗi (ví dụ kho hết hàng).
- Rollback về điểm lưu
book_reservedđể huỷ thay đổi liên quan đến cốc. - Cuối cùng, xác nhận thay đổi cho sách bằng
COMMIT.
Ví dụ nâng cao: xử lý dữ liệu nhiều bước
Bây giờ tưởng tượng bạn làm việc với hệ thống quản lý đơn hàng, cần cập nhật nhiều bảng: orders (đơn hàng), inventory (tồn kho) và billing (hóa đơn). Nếu một bước nào đó fail, bạn không muốn mất tiến trình ở các bảng khác. Đây là lúc SAVEPOINT phát huy tác dụng.
BEGIN;
-- Bước 1: Tạo đơn hàng mới
INSERT INTO orders (order_id, customer_id, status) VALUES (1, 123, 'đang chờ');
SAVEPOINT after_order_created;
-- Bước 2: Cập nhật tồn kho
UPDATE inventory SET stock = stock - 2 WHERE product_id = 101;
SAVEPOINT after_stock_updated;
-- Bước 3: Thanh toán
INSERT INTO billing (order_id, amount, status) VALUES (1, 100, 'đã thanh toán');
-- Ôi, lỗi: thẻ tín dụng bị từ chối!
ROLLBACK TO SAVEPOINT after_stock_updated;
-- Quay lại sau khi cập nhật tồn kho, đơn hàng vẫn ở trạng thái "đang chờ".
UPDATE orders SET status = 'thất bại' WHERE order_id = 1;
COMMIT;
Chú ý cách dùng SAVEPOINT để chia nhỏ giao dịch thành các bước logic và quay lại đúng điểm cần thiết, giữ lại một phần thay đổi.
Mẹo hữu ích khi dùng SAVEPOINT
- Đặt tên điểm lưu có ý nghĩa. Như ví dụ trên,
after_order_createdrõ ràng hơn nhiều so vớistep1. - Có thể lồng nhiều điểm lưu: bạn tạo
SAVEPOINTngay cả khi đã rollback về một điểm khác. - Giải phóng tài nguyên bằng cách xoá điểm không cần thiết qua
RELEASE SAVEPOINT. Điều này giúp tăng hiệu năng, nhất là với giao dịch lớn.
Kịch bản thực tế
Xử lý giao dịch ngân hàng: Ví dụ, khi chuyển tiền giữa nhiều tài khoản, bạn có thể rollback về một bước nếu một giao dịch bị lỗi.
Import dữ liệu từ file: Nếu bạn import một file CSV lớn, bạn có thể kiểm tra từng dòng và rollback chỉ những dòng lỗi, giữ lại các dòng thành công.
Cập nhật hàng loạt bản ghi: Nếu bạn có một script SQL phức tạp để update hàng ngàn dòng, SAVEPOINT cho phép rollback về bước trước nếu có lỗi giữa chừng.
Lỗi thường gặp và bẫy
Đôi khi dùng SAVEPOINT có thể gây ra kết quả bất ngờ nếu bạn chưa hiểu rõ cách nó hoạt động. Ví dụ:
- Nếu bạn quên rollback về điểm lưu hoặc xoá nó, có thể dẫn đến tình trạng tài nguyên bị khoá cho đến khi giao dịch kết thúc.
SAVEPOINTkhông thể huỷ các thao tác đã xảy ra trước khi tạo điểm lưu. Ví dụ, dữ liệu đã xác nhận quaCOMMITthì không thể rollback nữa.
Bây giờ bạn đã có thể tự tin thử nghiệm với giao dịch, tạo điểm lưu ở chỗ cần thiết. Sắp tới còn nhiều bài tập SQL thực chiến nữa, chuẩn bị tinh thần cho những thử thách tiếp theo nha!
GO TO FULL VERSION