首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP MySQL 事務處理實現轉賬功能:ACID 原則實戰演示

     編輯:PHP 綜合知識

事務處理核心概念

轉賬操作必須滿足 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 字段)解決併發衝突。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved