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

PHP 實現 MySQL 事務處理完整示例:START TRANSACTION、COMMIT、ROLLBACK 與錯誤回滾模式

     編輯:PHP 相關知識

PHP 實現 MySQL 事務處理完整示例

事務保證一組 SQL 操作的原子性(全成功或全失敗),是電商訂單、銀行轉賬、庫存扣減等核心業務的基石。本文基於 MySQL 5.6+ / PHP 5.6+,使用 InnoDB 引擎,展示標準事務模式與錯誤自動回滾封裝。

前置條件

  • 表引擎必須為 InnoDB(MyISAM 不支持事務)。
  • PHP 使用 mysqli 或 PDO(本文示例用 mysqli 過程風格,便於理解)。

基礎事務流程

<?php
$link = mysqli_connect('localhost:3307', 'root', 'password', 'web_his');
mysqli_set_charset($link, 'utf8');

// 1. 開啟事務
mysqli_query($link, 'START TRANSACTION') or exit(mysqli_error($link));

// 2. 執行業務 SQL 1
$sql1 = "INSERT INTO pf_item VALUES ('22', '我們', '30')";
if (!mysqli_query($link, $sql1)) {
    echo "SQL1 失敗: " . mysqli_error($link) . "
"; mysqli_query($link, 'ROLLBACK') or exit(mysqli_error($link)); exit; } // 3. 執行業務 SQL 2 $sql2 = "INSERT INTO pf_item VALUES ('21', 'hell', '10')"; if (!mysqli_query($link, $sql2)) { echo "SQL2 失敗: " . mysqli_error($link) . "
"; mysqli_query($link, 'ROLLBACK') or exit(mysqli_error($link)); exit; } // 4. 全部成功,提交事務 mysqli_query($link, 'COMMIT') or exit(mysqli_error($link)); mysqli_close($link); echo "事務提交成功"; ?>

進階:封裝通用事務執行器

<?php
/**
 * 執行一組 SQL 事務
 * @param mysqli $link
 * @param array $sqls  SQL 語句數組
 * @return bool|array 成功返回 true,失敗返回 [false, error_msg, failed_sql]
 */
function executeTransaction(mysqli $link, array $sqls) {
    mysqli_query($link, 'START TRANSACTION');
    foreach ($sqls as $sql) {
        if (!mysqli_query($link, $sql)) {
            $err = mysqli_error($link);
            mysqli_query($link, 'ROLLBACK');
            return [false, $err, $sql];
        }
    }
    mysqli_query($link, 'COMMIT');
    return true;
}

// 使用示例
$link = mysqli_connect('localhost', 'root', 'pwd', 'db');
mysqli_set_charset($link, 'utf8');

$res = executeTransaction($link, [
    "INSERT INTO orders (user_id, total) VALUES (100, 299.00)",
    "INSERT INTO order_items (order_id, product_id, qty) VALUES (LAST_INSERT_ID(), 5, 2)",
    "UPDATE products SET stock = stock - 2 WHERE id = 5 AND stock >= 2"
]);

if ($res === true) {
    echo "下單成功";
} else {
    list(, $err, $sql) = $res;
    echo "下單失敗: $err \nSQL: $sql";
}
?>

PDO 版本(推薦現代項目)

<?php
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8', 'root', 'pwd', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

try {
    $pdo->beginTransaction();

    $pdo->exec("INSERT INTO orders (user_id, total) VALUES (100, 299.00)");
    $orderId = $pdo->lastInsertId();
    $pdo->exec("INSERT INTO order_items (order_id, product_id, qty) VALUES ($orderId, 5, 2)");
    $pdo->exec("UPDATE products SET stock = stock - 2 WHERE id = 5 AND stock >= 2");

    $pdo->commit();
    echo "成功";
} catch (Exception $e) {
    $pdo->rollBack();
    echo "失敗: " . $e->getMessage();
}
?>

關鍵注意事項

  1. 自動提交模式:mysqli/PDO 默認 autocommit=ON,START TRANSACTION / beginTransaction() 會暫時關閉,COMMIT/commit() 恢復。
  2. 隱式提交:DDL 語句(CREATE/DROP/ALTER TABLE)、TRUNCATE、LOCK TABLES 會導致隱式提交,事務中避免使用。
  3. 死鎖處理:InnoDB 自動檢測死鎖並回滾其中一個事務,應用層捕獲 SQLSTATE[HY000]: General error: 1213 Deadlock 可重試。
  4. 長事務危害:持有鎖時間長、阻塞其他事務、Undo Log 膨脹。業務邏輯移出事務,只在事務中執行必要的寫操作。
  5. 異常安全:PDO 異常模式 + try/catch 確保 rollBack() 必被調用,避免事務懸掛。

事務是數據一致性的守門員,正確使用模式 + 異常安全封裝,讓核心業務經得起高併發考驗。

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