- Transaction là gì và vì sao rất quan trọng
- Ví dụ thực tế rất dễ toang
- Điều kiện để transaction hoạt động
- Cấu trúc transaction chuẩn
- Ví dụ transaction với PDO
- Vì sao phải dùng exception
- Kiểm tra logic không phải lỗi SQL
- Transaction với mysqli (nếu không dùng PDO)
- Những sai lầm cần tránh
- Khi nào nên dùng transaction
- Kết luận
Transaction là gì và vì sao rất quan trọng
Transaction là cơ chế cho phép bạn gom nhiều câu lệnh SQL thành một khối nguyên tử:
- Tất cả cùng thành công → commit
- Chỉ cần một câu lỗi → rollback toàn bộ
Không có transaction, database rất dễ rơi vào trạng thái nửa sống nửa chết.
Ví dụ thực tế rất dễ toang
Giả sử bạn cần:
- Tạo đơn hàng
- Trừ tồn kho sản phẩm
Nếu đơn hàng tạo xong nhưng trừ kho lỗi thì sao? Chúc mừng, dữ liệu đã sai vĩnh viễn.
Điều kiện để transaction hoạt động
- MySQL dùng engine InnoDB
- Không dùng MyISAM
- Dùng
PDOhoặcmysqli
Nếu bảng không phải InnoDB thì gọi transaction chỉ để… cho vui.
Cấu trúc transaction chuẩn
Transaction luôn có 3 bước:
- Begin transaction
- Thực hiện các câu SQL
- Commit hoặc rollback
Ví dụ transaction với PDO
<?php
$pdo = new PDO(
'mysql:host=localhost;dbname=shop;charset=utf8mb4',
'user',
'password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]
);
try {
// 1. bắt đầu transaction
$pdo->beginTransaction();
// 2. tạo đơn hàng
$stmt = $pdo->prepare("
INSERT INTO orders (user_id, total_amount)
VALUES (?, ?)
");
$stmt->execute([123, 500000]);
$orderId = $pdo->lastInsertId();
// 3. trừ tồn kho
$stmt = $pdo->prepare("
UPDATE products
SET stock = stock - 1
WHERE id = ? AND stock > 0
");
$stmt->execute([45]);
if ($stmt->rowCount() !== 1) {
throw new Exception('Không đủ tồn kho');
}
// 4. mọi thứ ok → commit
$pdo->commit();
} catch (Throwable $e) {
// có lỗi → rollback
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
die('Giao dịch thất bại: ' . $e->getMessage());
}
Vì sao phải dùng exception
Transaction chỉ thực sự hiệu quả khi:
- Bất kỳ lỗi nào cũng ném exception
- Không để code chạy tiếp trong trạng thái sai
Dùng PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION là bắt buộc, không thương lượng.
Kiểm tra logic không phải lỗi SQL
Nhiều trường hợp SQL không lỗi nhưng logic sai, ví dụ:
- Không đủ tồn kho
- Dữ liệu không hợp lệ
Lúc này, cần tự throw exception để rollback:
<?php
if ($stmt->rowCount() !== 1) {
throw new Exception('Logic không hợp lệ');
}
Transaction với mysqli (nếu không dùng PDO)
<?php
$mysqli->begin_transaction();
try {
$mysqli->query("INSERT INTO orders (...) VALUES (...)");
$mysqli->query("UPDATE products SET stock = stock - 1 WHERE id = 45");
$mysqli->commit();
} catch (Throwable $e) {
$mysqli->rollback();
throw $e;
}
Những sai lầm cần tránh
- Quên commit
- Catch lỗi nhưng không rollback
- Dùng transaction với bảng MyISAM
- Viết SQL ngoài transaction mà tưởng đang an toàn
Khi nào nên dùng transaction
- Ghi dữ liệu vào nhiều bảng liên quan
- Thanh toán, đơn hàng, điểm thưởng
- Bất kỳ logic nào không được phép sai lệch
Kết luận
Transaction không phải thứ cao siêu, nhưng là ranh giới giữa backend chuyên nghiệp và code cầu may. Chỉ cần áp dụng đúng, bạn sẽ tránh được 90% thảm hoạ dữ liệu mà nhiều hệ thống phải trả giá bằng máu và nước mắt.
Nhớ kỹ: đã ghi nhiều thứ liên quan với nhau, thì hoặc sống cùng nhau, hoặc chết cùng nhau!
Bình luận