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

PHP 實現 MySQL 事務處理:保證多表操作數據一致性

     編輯:PHP 綜合知識

在用戶註冊初始化多張關聯表、問答系統同時寫入問題與回答等場景中,若部分 SQL 執行成功、部分失敗,將導致數據不一致(如用戶表已插入但權限表未建立)。MySQL 事務(Transaction)通過「全成功提交、一失敗回滾」特性完美解決此問題。本文封裝一個通用的批量 SQL 事務執行方法。

核心代碼實作

<?php
class Database {
    private $conn;

    public function __construct($host, $user, $pass, $dbname) {
        $this->conn = new mysqli($host, $user, $pass, $dbname);
        if ($this->conn->connect_error) {
            die("連接失敗: " . $this->conn->connect_error);
        }
        $this->conn->set_charset('utf8mb4');
    }

    /**
     * 批量執行 SQL 事務
     * @param array $sqls SQL 語句陣列
     * @return bool true: 全部成功提交, false: 已回滾
     */
    public function executeTransaction(array $sqls): bool {
        $this->conn->autocommit(false); // 關閉自動提交
        $results = [];

        try {
            foreach ($sqls as $sql) {
                $res = $this->conn->query($sql);
                $results[] = $res !== false;
                if (!$res) {
                    throw new Exception("SQL 執行失敗: {$this->conn->error} | SQL: $sql");
                }
            }
            $this->conn->commit(); // 全部成功提交
            return true;
        } catch (Exception $e) {
            $this->conn->rollback(); // 任一失敗回滾
            error_log("事務回滾: " . $e->getMessage());
            return false;
        } finally {
            $this->conn->autocommit(true); // 恢復自動提交
        }
    }

    public function close() {
        $this->conn->close();
    }
}

// 使用範例
$db = new Database('localhost', 'root', 'password', 'my_db');
$sqls = [
    "INSERT INTO users (username, email) VALUES ('john', 'john@example.com')",
    "INSERT INTO profiles (user_id, bio) VALUES (LAST_INSERT_ID(), 'Hello')",
    "INSERT INTO user_roles (user_id, role_id) VALUES (LAST_INSERT_ID(), 2)"
];
if ($db->executeTransaction($sqls)) {
    echo "註冊成功,事務已提交";
} else {
    echo "註冊失敗,已回滾";
}
$db->close();

關鍵點解析

  1. 關閉自動提交:autocommit(false) 開啟事務模式,MySQL 預設自動提交每條 SQL。
  2. 異常捕獲回滾:使用 try-catch 捕獲執行失敗,統一呼叫 rollback()。
  3. 結果驗證:query() 返回 false 表示失敗,需顯式判斷。
  4. 恢復狀態:finally 區塊確保 autocommit(true) 執行,避免影響後續操作。
  5. 錯誤日誌:記錄失敗 SQL 及錯誤訊息,便於排查。

進階擴展:支援預處理語句

防止 SQL 注入,建議改用 prepare() + bind_param():

public function executePreparedTransaction(array $statements): bool {
    // $statements = [['sql' => 'INSERT ...', 'params' => [...], 'types' => 'ssi'], ...]
    $this->conn->autocommit(false);
    try {
        foreach ($statements as $stmtData) {
            $stmt = $this->conn->prepare($stmtData['sql']);
            if ($stmtData['params']) {
                $stmt->bind_param($stmtData['types'], ...$stmtData['params']);
            }
            if (!$stmt->execute()) {
                throw new Exception($stmt->error);
            }
            $stmt->close();
        }
        $this->conn->commit();
        return true;
    } catch (Exception $e) {
        $this->conn->rollback();
        return false;
    } finally {
        $this->conn->autocommit(true);
    }
}

注意事項

  • 事務僅支援 InnoDB 引擎表,MyISAM 不支援。
  • 長事務會鎖定資源,影響併發,業務邏輯應盡量精簡。
  • 異常情況下(如進程崩潰、死鎖),MySQL 會自動回滾未提交事務。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved