首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

PHP + MySQL 事務處理:從原理到模擬實現的完整指南

     編輯:MySQL 資料庫相關知識

前言:為什麼需要事務?

資料庫如同感情關係:承諾永久,卻可能中途崩潰。事務技術確保「要麼全做,要麼全不做」,在多表更新、訂單生成、扣款轉賬等關鍵業務中不可或缺。MySQL 早期版本(3.22)不支援事務,開發者需自行模擬;現代版本(5.6+)InnoDB 已完美支援 ACID。

一、事務核心概念 (ACID)

  • 原子性:不可分割的最小工作單元。
  • 一致性:事務前後資料完整性約束保持滿足。
  • 隔離性:並發事務互不干擾(四大隔離級別)。
  • 持久性:提交後永久生效,掉電不丟失。

二、經典場景:購物車結算

-- 業務流程:
-- 1. 生成訂單主表
-- 2. 寫入訂單明細(多筆)
-- 3. 清空購物車
-- 若第 2 步失敗,訂單主表不應存在;若第 3 步失敗,購物車殘留導致重複下單。

三、MySQL 事務標準語法 (InnoDB)

<?php
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8mb4', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

try {
    $pdo->beginTransaction();  // 開啟事務

    // 1. 插入訂單主表
    $stmt = $pdo->prepare('INSERT INTO orders (user_id, total, created_at) VALUES (?, ?, NOW())');
    $stmt->execute([$uid, $total]);
    $orderId = $pdo->lastInsertId();

    // 2. 批量插入明細
    $stmt = $pdo->prepare('INSERT INTO order_items (order_id, product_id, qty, price) VALUES (?, ?, ?, ?)');
    foreach ($cartItems as $item) {
        $stmt->execute([$orderId, $item['pid'], $item['qty'], $item['price']]);
    }

    // 3. 清空購物車
    $pdo->exec("DELETE FROM cart WHERE user_id = $uid");

    $pdo->commit();  // 全部成功,提交
    echo '下單成功,訂單號: ' . $orderId;

} catch (Exception $e) {
    $pdo->rollBack();  // 任一失敗,回滾
    echo '下單失敗: ' . $e->getMessage();
}
?>

四、早期 MyISAM 不支援事務的模擬方案(歷史參考)

  1. 應用層補償:記錄操作日誌,失敗時執行反向 SQL(如刪除已插入行、恢復已修改值)。
  2. 狀態機法:訂單表加 status 欄位(0=處理中, 1=完成, 2=失敗),定時掃描處理中單據重試或回滾。
  3. 鎖表模擬:LOCK TABLES orders WRITE, items WRITE, cart WRITE ... UNLOCK TABLES(效能極差,強烈不推薦)。

結論: 早期專案務必升級 InnoDB,勿再造輪子。

五、進階主題:隔離級別與死鎖處理

  • READ COMMITTED(RC):大多數場景推薦,鎖衝突少。
  • REPEATABLE READ(RR):InnoDB 預設,解決幻讀靠 Gap Lock,易死鎖。
  • 死鎖排查:SHOW ENGINE INNODB STATUS 分析,統一加鎖順序、縮短事務、避免長事務。

六、總結

事務是資料庫可靠性的基石。現代 PHP + MySQL 開發請直接使用 PDO 事務 API(beginTransaction/commit/rollBack),配合 InnoDB 引擎、RC 隔離級別、預處理語句,即可構建健壯的業務系統。切記:事務要短、要快、要少鎖。

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