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

PHP PDO MySQL 事務處理完整實戰指南

     編輯:PHP 相關知識

為什麼選擇 PDO 進行事務管理?

PDO (PHP Data Objects) 提供了統一的資料庫訪問介面,支援預處理語句、異常模式、事務控制等現代特性。相比傳統 mysql_* 函數,PDO 更安全、可移植,是目前 PHP 專案的推薦選擇。

事務處理核心流程

  1. 關閉自動提交:PDO::ATTR_AUTOCOMMIT => false 或 $pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0)。
  2. 開啟事務:$pdo->beginTransaction()。
  3. 執行業務 SQL:使用 exec()(增刪改)或 prepare()/execute()(參數化查詢)。
  4. 異常捕獲與回滾:try-catch 捕獲 PDOException,調用 $pdo->rollBack()。
  5. 提交事務:所有操作成功後 $pdo->commit()。
  6. 恢復自動提交:$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1)。

完整代碼範例:模擬轉賬業務

<?php
// 1. 建立連接,關閉自動提交,啟用異常模式
$dsn = "mysql:host=127.0.0.1;dbname=test_db;charset=utf8mb4";
$user = "root";
$pass = "password";
try {
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_AUTOCOMMIT => 0,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
    ]);
} catch (PDOException $e) {
    die("資料庫連接失敗:" . $e->getMessage());
}

// 2. 業務邏輯:張三轉賬 500 元給李四
try {
    $pdo->beginTransaction();

    $amount = 500;
    $fromId = 1; // 張三
    $toId   = 3; // 李四

    // 扣款
    $sql = "UPDATE `account` SET `balance` = `balance` - :amt WHERE `id` = :id AND `balance` >= :amt";
    $stmt = $pdo->prepare($sql);
    $stmt->bindValue(':amt', $amount, PDO::PARAM_INT);
    $stmt->bindValue(':id', $fromId, PDO::PARAM_INT);
    $stmt->execute();
    if ($stmt->rowCount() === 0) {
        throw new PDOException("張三餘額不足或賬戶不存在");
    }

    // 入賬
    $sql = "UPDATE `account` SET `balance` = `balance` + :amt WHERE `id` = :id";
    $stmt = $pdo->prepare($sql);
    $stmt->bindValue(':amt', $amount, PDO::PARAM_INT);
    $stmt->bindValue(':id', $toId, PDO::PARAM_INT);
    $stmt->execute();
    if ($stmt->rowCount() === 0) {
        throw new PDOException("李四賬戶不存在");
    }

    // 記錄流水(可選)
    $sql = "INSERT INTO `transfer_log` (`from_id`, `to_id`, `amount`, `created_at`) VALUES (:from, :to, :amt, NOW())";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([':from' => $fromId, ':to' => $toId, ':amt' => $amount]);

    $pdo->commit();
    echo "轉賬成功!";
} catch (PDOException $e) {
    $pdo->rollBack();
    echo "轉賬失敗:" . $e->getMessage();
} finally {
    // 3. 恢復自動提交(可選,視連接復用策略)
    $pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
}
?>

關鍵技術點深度解析

1. 存儲引擎必須支援事務

MySQL 中僅 InnoDB 支援事務,MyISAM、Memory 等不支援。建表時指定 ENGINE=InnoDB,或執行 ALTER TABLE t ENGINE=InnoDB 遷移。

2. 行級鎖與死鎖預防

  • 更新語句務必走索引(如主鍵 id),避免全表鎖升級。
  • 多表操作保持一致的加鎖順序(如先 from_id 再 to_id),降低死鎖概率。
  • 捕獲 SQLSTATE[HY000]: General error: 1213 Deadlock found 可重試機制。

3. 隔離級別與一致性讀

InnoDB 預設 REPEATABLE READ(可重複讀),配合 MVCC 實現一致性非鎖定讀。如需更高隔離可執行:

$pdo->exec("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED");

4. 預處理語句的效能優勢

  • 同一 SQL 多次執行只解析一次,減少 CPU 開銷。
  • 參數綁定自動處理轉義,徹底防止 SQL 注入。
  • 使用 bindValue(值綁定)而非 bindParam(引用綁定),避免循環中變量引用導致的邏輯錯誤。

5. 錯誤模式選擇

模式常量適用場景
靜默PDO::ERRMODE_SILENT不推薦,需手動檢查 errorInfo()
警告PDO::ERRMODE_WARNING開發調試,不中斷執行
異常PDO::ERRMODE_EXCEPTION生產環境推薦,配合 try-catch 統一處理

進階技巧:嵌套事務與 Savepoint

PDO 不原生支援嵌套事務,但可用 Savepoint 模擬:

$pdo->beginTransaction();
// ... 外層操作
$pdo->exec("SAVEPOINT sp1");
try {
    // ... 內層操作
    $pdo->exec("RELEASE SAVEPOINT sp1");
} catch (Exception $e) {
    $pdo->exec("ROLLBACK TO SAVEPOINT sp1");
    // 決定是否繼續外層事務
}
$pdo->commit();

總結

PDO 事務處理的核心在於「關閉自動提交 → 開啟事務 → 業務操作 → 成功提交/失敗回滾 → 恢復自動提交」。配合預處理語句、異常模式、InnoDB 行級鎖,能構建高可靠、高併發的資料庫應用。實際專案中建議封裝 Db::transaction(callable $callback) 輔助方法,統一異常處理與日誌記錄,減少樣板代碼。

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