Không có transaction ACID nào chạy qua hai database độc lập, nên phải chọn giữa hai mô hình.
2PC (two-phase commit) — một coordinator hỏi tất cả bên tham gia "sẵn sàng commit chưa?" (prepare), nếu tất cả trả lời sẵn sàng thì mới ra lệnh commit.
- Được: giữ tính nguyên tử thật, ứng dụng không phải tự viết logic bù trừ.
- Mất: các bên giữ khoá xuyên suốt giai đoạn prepare; coordinator chết giữa chừng thì các bên kẹt ở trạng thái nghi ngờ, khoá không nhả cho tới khi có người can thiệp. Tính sẵn sàng của hệ thống bằng tích của tất cả các bên.
Saga — chuỗi các transaction cục bộ, mỗi bước commit ngay; bước nào lỗi thì chạy các giao dịch bù trừ để đảo ngược các bước trước (hoàn tiền, trả hàng về kho).
- Được: không giữ khoá phân tán, mỗi service tự chủ, chịu lỗi và scale tốt hơn.
- Mất: không có isolation — người dùng có thể quan sát được trạng thái trung gian (đơn đã tạo nhưng chưa thanh toán). Bạn phải tự thiết kế bù trừ, và có thao tác không đảo ngược được (mail đã gửi).
Chọn thế nào: trong một hệ đóng, ít bên tham gia, độ trễ thấp, cần nguyên tử tuyệt đối và chấp nhận đánh đổi tính sẵn sàng thì 2PC hợp lý. Với microservices qua mạng, số bên nhiều hoặc có bên là API bên thứ ba thì saga là mặc định — kèm outbox để phát sự kiện đáng tin và khoá idempotency để mỗi bước chạy lại được an toàn.
Câu hỏi nên đặt trước cả hai: hai phần dữ liệu này có thật sự phải nằm ở hai database không? Gộp về cùng một database để dùng transaction cục bộ thường là lời giải rẻ nhất.