轉賬操作必須滿足 ACID 特性:
需使用 **InnoDB** 存儲引擎(MyISAM 不支援事務)。
autocommit(false);
// 2. 查詢轉出戶餘額
$result = $mysqli->query("SELECT cash FROM account WHERE name='userA'");
$row = $result->fetch_assoc();
$balance = $row['cash'];
if ($balance < $price) {
echo '餘額不足';
$mysqli->close();
exit();
}
// 3. 執行扣款
$result = $mysqli->query("UPDATE account SET cash=cash-$price WHERE name='userA'");
if (!$result || $mysqli->affected_rows != 1) $success = false;
// 4. 執行入賬
$result = $mysqli->query("UPDATE account SET cash=cash+$price WHERE name='userB'");
if (!$result || $mysqli->affected_rows != 1) $success = false;
// 5. 提交或回滾
if ($success) {
$mysqli->commit();
echo '轉賬成功!';
} else {
$mysqli->rollback();
echo "轉賬失敗!";
}
// 6. 恢復自動提交
$mysqli->autocommit(true);
// 7. 驗證結果(預處理語句防注入)
$stmt = $mysqli->prepare("SELECT cash FROM account WHERE name=?");
$stmt->bind_param('s', $name);
$name = 'userA';
$stmt->execute();
$stmt->bind_result($cash);
$stmt->fetch();
echo "用戶 userA 餘額:$cash";
$mysqli->close();
CREATE TABLE account (
userID SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NOT NULL,
cash DECIMAL(9,2) NOT NULL,
PRIMARY KEY (userID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO account (name, cash) VALUES ('userA', 2000), ('userB', 10000);
| 關鍵操作 | 作用 | 注意事項 |
|---|---|---|
| `autocommit(false)` | 開啟事務 | 必須在查詢前調用 |
| `affected_rows` | 驗證影響行數 | 防止 WHERE 條件不匹配導致靜默失敗 |
| `commit()` | 持久化變更 | 之前的操作對其他事務可見 |
| `rollback()` | 撤銷變更 | 釋放行鎖,恢復原狀態 |
| 預處理語句 | 防 SQL 注入 | 業務邏輯後驗證餘額時使用 |
function transferWithRetry($mysqli, $from, $to, $amount, $maxRetries = 3) {
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
$mysqli->autocommit(false);
try {
// ... 執行轉賬邏輯 ...
$mysqli->commit();
return true;
} catch (mysqli_sql_exception $e) {
$mysqli->rollback();
if ($e->getCode() == 1213 && $attempt < $maxRetries) { // Deadlock
usleep(rand(10000, 50000)); // 隨機等待
continue;
}
throw $e;
} finally {
$mysqli->autocommit(true);
}
}
return false;
}
事務是金融級業務的基石。實際項目中建議:封裝 `TransactionManager` 類、使用 PDO 統一介面、引入分布式事務(TCC/Saga)應對微服務架構、配合樂觀鎖(version 字段)解決併發衝突。