CodeGym /Các khóa học /SQL SELF /Đào sâu vào giao dịch

Đào sâu vào giao dịch

SQL SELF
Mức độ , Bài học
Có sẵn

Tụi mình đã nhắc đến giao dịch ở mấy bài trước rồi. Nhắc lại cho chắc: giao dịch là một chuỗi thao tác phải thực hiện như một khối duy nhất. Ví dụ như chuyển khoản ngân hàng ấy. Lúc đó mình trừ tiền ở một tài khoản và cộng vào tài khoản khác. Nếu một bước nào đó fail (kiểu trừ tiền rồi mà chưa cộng được), thì toang luôn. Đây là lúc giao dịch cứu cánh cho mình.

Giao dịch hoặc là thực hiện toàn bộ, hoặc là không làm gì hết. Đó gọi là nguyên tắc "tất cả hoặc không gì cả".

BEGIN;
-- Giảm số dư ở một tài khoản
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- Tăng số dư ở tài khoản khác
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT; -- Áp dụng thay đổi

Nếu có gì đó không ổn, bạn có thể hoàn tác thay đổi bằng ROLLBACK.

ACID là gì trong giao dịch

Khi nói về giao dịch trong PostgreSQL (và nói chung là database quan hệ), tụi mình hay nhắc đến từ viết tắt ACID — không phải hóa học đâu nha. ACID là viết tắt của Atomicity (tính nguyên tử), Consistency (tính nhất quán), Isolation (tính cô lập), Durability (tính bền vững). Bốn thuộc tính này đảm bảo dữ liệu được xử lý an toàn, tuần tự và không có bất ngờ nào hết.

Tính nguyên tử (Atomicity)
Giao dịch hoặc chạy hết, hoặc không chạy gì cả. Nếu có gì đó fail bên trong — mọi thứ sẽ bị hoàn tác. Ví dụ: bạn chuyển tiền mà bị lỗi — hoặc là hủy hết, hoặc là chuyển thành công. Không có chuyện "nửa vời" đâu nha.

Tính nhất quán (Consistency)
Sau khi giao dịch xong, database vẫn ở trạng thái hợp lệ, logic. Tất cả rule, constraint và liên kết giữa các bảng phải được giữ nguyên. Ví dụ, nếu không cho phép số dư âm, giao dịch vi phạm sẽ không được lưu lại.

Tính cô lập (Isolation)
Khi một giao dịch chưa xong, giao dịch khác không được thấy dữ liệu tạm thời của nó. Điều này tránh mấy hiệu ứng kỳ lạ, kiểu bạn thấy dữ liệu "lưng chừng". Ví dụ, trong shop online, tiền đã bị trừ mà hàng chưa thêm vào đơn — ai mà thích kiểu đó đâu?

Tính bền vững (Durability)
Nếu giao dịch thành công, mọi thay đổi chắc chắn được lưu lại. Dù có cúp điện ngay sau đó — dữ liệu vẫn còn trong database. Kiểu như bấm "Lưu" và yên tâm mọi thứ an toàn.

Bốn thuộc tính này chính là lý do giao dịch được xem là cơ chế siêu tin cậy khi làm việc với database.

Ví dụ thực tế dùng giao dịch

Lý thuyết thì hay, nhưng sức mạnh thật sự của giao dịch là ở các bài toán thực tế. Đặc biệt là mấy vụ liên quan đến tiền, bảng liên kết hoặc cập nhật hàng loạt — giao dịch là cứu tinh. Nó giúp bạn thao tác tự tin, không lo mất dữ liệu hay database bị "nửa sống nửa chết".

Dưới đây là vài ví dụ điển hình giao dịch thực sự cứu nguy:

1. Xử lý thanh toán

Khi khách chuyển tiền từ tài khoản này sang tài khoản khác, giao dịch đảm bảo tiền không bị "bốc hơi" đâu đó:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;

Nếu tài khoản đầu không đủ tiền, bạn có thể hoàn tác thay đổi:

BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE account_id = 1;
-- Ôi, số dư âm rồi!
ROLLBACK;

2. Cập nhật bảng liên kết

Giả sử bạn cập nhật trạng thái sinh viên thành "đã tốt nghiệp" và đồng thời thêm bản ghi vào bảng "tốt nghiệp":

BEGIN;
UPDATE students SET status = 'graduated' WHERE student_id = 42;
INSERT INTO graduates (student_id, graduation_date) VALUES (42, '2023-06-10');
COMMIT;

Nếu một thao tác fail (ví dụ lỗi ở INSERT), database sẽ quay lại trạng thái ban đầu.

3. Cập nhật dữ liệu hàng loạt

Giao dịch rất hữu ích khi cập nhật số lượng lớn, ví dụ:

BEGIN;
UPDATE orders SET status = 'completed' WHERE delivery_date < CURRENT_DATE;
COMMIT;

Nếu server sập hoặc bạn phát hiện cập nhật nhầm, bạn có thể hoàn tác bất cứ lúc nào!

Các lệnh thao tác giao dịch

PostgreSQL cung cấp vài lệnh chính:

  • BEGIN: bắt đầu một giao dịch mới:

    BEGIN;
    
  • COMMIT: xác nhận (lưu) mọi thay đổi trong giao dịch:

    COMMIT;
    

ROLLBACK: hoàn tác mọi thay đổi trong giao dịch hiện tại:

ROLLBACK;

Ví dụ một vòng giao dịch đầy đủ

BEGIN;
-- Một số thao tác
UPDATE accounts SET balance = balance - 200 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 200 WHERE account_id = 2;

-- Quyết định hoàn tác thay đổi
ROLLBACK;

-- Bắt đầu lại
BEGIN;
-- Vẫn thao tác đó, nhưng chuyển khoản khác
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;

-- Kết thúc giao dịch
COMMIT;

Giao dịch ngoài sách vở

Shop online. Nhiều nền tảng dùng giao dịch để quản lý đơn hàng và thanh toán. Ví dụ, đơn chỉ được xử lý khi thanh toán thành công. Nếu có gì đó fail, đơn sẽ tự động bị hủy.

Hệ thống ngân hàng. Giao dịch bảo vệ tiền của bạn khỏi mấy sự cố như cúp điện bất ngờ.

Lịch sử giao dịch. PostgreSQL lưu log WAL (Write-Ahead Logging) để phục hồi dữ liệu khi có sự cố. Đó là "ma thuật" giúp giao dịch siêu tin cậy.

Ở bài sau tụi mình sẽ phân tích kỹ hơn các lệnh BEGIN, COMMITROLLBACK, cũng như xem ví dụ thao tác hàng loạt và hoàn tác từng phần với SAVEPOINT. Hẹn gặp lại nhé!

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION