Transaction (giao dịch) trong database là một nhóm các thao tác SQL được thực thi như một đơn vị duy nhất. Tất cả các thao tác trong transaction phải thành công hoàn toàn hoặc thất bại hoàn toàn - không có trạng thái trung gian.
Sequelize cung cấp sequelize.transaction() để bắt đầu một transaction và trả về một Transaction object (thường đặt tên là t).
Tại sao cần dùng Transaction?
Transaction đảm bảo các đặc tính ACID:
Atomicity (Tính nguyên tử): Tất cả hoặc không có gì - không có trạng thái “làm một nửa” Consistency (Tính nhất quán): Database luôn ở trạng thái hợp lệ Isolation (Tính cô lập): Các transaction không ảnh hưởng lẫn nhau Durability (Tính bền vững): Dữ liệu đã commit không bị mất Ví dụ thực tế:
Cách sử dụng Manual Transaction
1. Pattern cơ bản
2. Ví dụ thực tế: Xóa Post và các ảnh liên quan
❌ Sai: Xóa không đồng bộ - Có thể gây lỗi
✅ Đúng: Dùng transaction và thứ tự hợp lý
Thứ tự quan trọng:
Xóa file/ảnh trên disk TRƯỚC Xóa records trong database SAU Lý do: Nếu xóa DB trước mà xóa file sau bị lỗi, bạn mất thông tin về file cần xóa. Ngược lại nếu xóa file trước mà DB sau bị lỗi, transaction rollback và bạn vẫn có thông tin để thử lại.
Managed Transaction (Auto-commit/rollback)
Thay vì quản lý commit() và rollback() thủ công, bạn có thể dùng callback pattern:
Sequelize thực chất làm như này (pseudo-code):
Ưu điểm:
Không lo quên commit() hoặc rollback() Nhược điểm:
Ít linh hoạt hơn với error handling phức tạp Ví dụ 1: Tạo Order với nhiều OrderItems
Ví dụ 2: Transfer tiền giữa 2 tài khoản
Ví dụ 3: Xóa User và tất cả dữ liệu liên quan
Ví dụ 4: Nested operations phức tạp
Khi nào dùng Managed vs Manual?
✅ Dùng Managed Transaction khi:
Không cần xử lý error phức tạp Muốn code ngắn gọn, dễ đọc Tất cả operations đều là DB queries ✅ Dùng Manual Transaction khi:
Cần control chi tiết việc commit/rollback Có logic phức tạp với nhiều điều kiện Cần cleanup resources đặc biệt khi rollback Kết hợp với file operations, external APIs Error Handling với Managed Transaction
Tóm tắt
Managed Transaction giống như một "khối bảo vệ tự động":
Bạn chỉ cần viết logic bên trong callback Sequelize tự lo commit nếu thành công Sequelize tự lo rollback nếu có lỗi Code ngắn gọn, ít lỗi hơn Nhớ: Mọi query bên trong callback PHẢI có { transaction: t } để được bao gồm trong transaction!
Best Practices
1. Luôn dùng try-catch với manual transactions
2. Giữ transaction ngắn gọn
3. Xử lý file operations cẩn thận
Tóm tắt
Transaction đảm bảo nhiều DB operations thành công hoàn toàn hoặc thất bại hoàn toàn Manual pattern: const t = await sequelize.transaction() → commit() / rollback() Managed pattern: sequelize.transaction(async (t) => { ... }) → auto-commit/rollback Quan trọng: Xóa file trước → Xóa DB sau, luôn dùng try-catch Best practice: Giữ transaction ngắn, chỉ DB operations, xử lý external calls bên ngoài