SAVEPOINT đánh dấu một điểm giữa transaction để có thể quay lui một phần thay vì huỷ toàn bộ.
BEGIN;
INSERT INTO orders (user_id, total) VALUES (42, 500);
SAVEPOINT try_coupon;
UPDATE coupons SET used = true WHERE code = 'SALE10';
-- coupon đã hết hạn → chỉ bỏ phần này
ROLLBACK TO SAVEPOINT try_coupon;
COMMIT; -- đơn hàng vẫn được ghiĐiểm cần nắm:
- Database quan hệ không có transaction lồng nhau thật sự. Chỉ có một transaction duy nhất; BEGIN lần thứ hai không tạo transaction mới.
- ORM (Hibernate, EF Core, Django, Drizzle...) mô phỏng "nested transaction" bằng savepoint: khối trong cùng khi lỗi thì ROLLBACK TO SAVEPOINT, khối ngoài cùng mới thật sự COMMIT.
- Hệ quả quan trọng: đã COMMIT khối trong mà khối ngoài rollback thì mọi thứ vẫn mất. Đừng thiết kế logic dựa trên giả định khối trong đã "chốt".
- Trong PostgreSQL, một lỗi SQL làm transaction chuyển sang trạng thái abort, mọi câu sau đều lỗi cho tới khi rollback. Savepoint là cách duy nhất để thử một thao tác có thể lỗi rồi đi tiếp mà không mất phần đã làm.