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

PHP mysqli 擴展操作 MySQL 完全指南:面向對象、面向過程與封裝類實戰

     編輯:PHP 相關知識

mysqli 擴展優勢

  • 支持 預處理語句,有效防止 SQL 注入
  • 提供 面向對象 與 面向過程 雙重 API
  • 支持 事務控制、多語句執行、增強的調試能力
  • MySQL 4.1+ 官方推薦擴展 (舊 mysql_* 已棄用移除)

一、面向對象風格 (推薦)

<?php
header("Content-Type: text/html; charset=utf-8");

// 1. 創建連接對象
$mysqli = new MySQLi("localhost", "root", "root", "test");

// 2. 檢查連接錯誤
if ($mysqli->connect_error) {
    die("連接失敗: " . $mysqli->connect_error);
}

// 3. 設置字符集 (防止中文亂碼)
$mysqli->set_charset("utf8mb4");

// 4. 執行 DQL 查詢
$sql = "SELECT * FROM user1";
$res = $mysqli->query($sql);

if ($res) {
    // 遍歷結果集 (關聯數組)
    while ($row = $res->fetch_assoc()) {
        var_dump($row);
        // echo "ID: {$row['id']}, Name: {$row['name']}
"; } // 釋放結果集內存 $res->free(); } else { echo "查詢失敗: " . $mysqli->error; } // 5. 關閉連接 $mysqli->close(); ?>

二、面向過程風格

<?php
header("Content-Type: text/html; charset=utf-8");

$mysqli = mysqli_connect("localhost", "root", "root", "test");
if (!$mysqli) {
    die("連接失敗: " . mysqli_connect_error());
}

mysqli_set_charset($mysqli, "utf8mb4");

$sql = "SELECT * FROM user1";
$res = mysqli_query($mysqli, $sql);

if ($res) {
    while ($row = mysqli_fetch_assoc($res)) {
        foreach ($row as $val) {
            echo "- $val ";
        }
        echo "
"; } mysqli_free_result($res); } else { echo "查詢失敗: " . mysqli_error($mysqli); } mysqli_close($mysqli); ?>

三、DML 操作 (增/刪/改) 與事務

<?php
$mysqli = new MySQLi("localhost", "root", "root", "test");
if ($mysqli->connect_error) die("連接失敗: " . $mysqli->connect_error);
$mysqli->set_charset("utf8mb4");

// 開啟事務
$mysqli->begin_transaction();

try {
    // 插入
    $sql = "INSERT INTO user1 (name, password, email, age) VALUES ('lucy', MD5('lucy'), 'lucy@163.com', 17)";
    if (!$mysqli->query($sql)) throw new Exception("插入失敗: " . $mysqli->error);

    // 更新
    $sql = "UPDATE user1 SET age = 20 WHERE id = 7";
    if (!$mysqli->query($sql)) throw new Exception("更新失敗: " . $mysqli->error);

    // 刪除
    $sql = "DELETE FROM user1 WHERE id = 80";
    if (!$mysqli->query($sql)) throw new Exception("刪除失敗: " . $mysqli->error);

    // 提交事務
    $mysqli->commit();
    echo "事務提交成功,影響行數: " . $mysqli->affected_rows;
} catch (Exception $e) {
    $mysqli->rollback();
    echo "事務回滾: " . $e->getMessage();
}

$mysqli->close();
?>

四、預處理語句 (防注入最佳實踐)

<?php
$mysqli = new MySQLi("localhost", "root", "root", "test");
$mysqli->set_charset("utf8mb4");

// 準備語句
$stmt = $mysqli->prepare("INSERT INTO user1 (name, email, age) VALUES (?, ?, ?)");
if (!$stmt) die("準備失敗: " . $mysqli->error);

// 綁定參數: s=字符串, i=整數, d=雙精度, b=blob
$name = "tom";
$email = "tom@example.com";
$age = 25;
$stmt->bind_param("ssi", $name, $email, $age);

// 執行
if ($stmt->execute()) {
    echo "插入成功, ID: " . $stmt->insert_id;
} else {
    echo "執行失敗: " . $stmt->error;
}

$stmt->close();
$mysqli->close();
?>

五、數據庫操作封裝類 (SqlHelper)

<?php
class SqlHelper {
    private $mysqli;
    // 配置常量 (生產環境建議從配置文件讀取)
    private const HOST = 'localhost';
    private const USER = 'root';
    private const PWD  = 'root';
    private const DB   = 'test';

    public function __construct() {
        $this->mysqli = new MySQLi(self::HOST, self::USER, self::PWD, self::DB);
        if ($this->mysqli->connect_error) {
            die("DB 連接失敗: " . $this->mysqli->connect_error);
        }
        $this->mysqli->set_charset("utf8mb4");
    }

    // DQL 查詢: 返回 mysqli_result 對象
    public function executeDQL(string $sql) {
        $res = $this->mysqli->query($sql);
        if (!$res) {
            throw new Exception("查詢失敗: " . $this->mysqli->error);
        }
        return $res;
    }

    // DML 增刪改: 返回影響行數
    public function executeDML(string $sql): int {
        $res = $this->mysqli->query($sql);
        if (!$res) {
            throw new Exception("執行失敗: " . $this->mysqli->error);
        }
        return $this->mysqli->affected_rows;
    }

    // 獲取單條記錄 (關聯數組)
    public function fetchOne(string $sql): ?array {
        $res = $this->executeDQL($sql);
        $row = $res->fetch_assoc();
        $res->free();
        return $row ?: null;
    }

    // 獲取所有記錄 (關聯數組數組)
    public function fetchAll(string $sql): array {
        $res = $this->executeDQL($sql);
        $data = $res->fetch_all(MYSQLI_ASSOC);
        $res->free();
        return $data;
    }

    // 預處理查詢
    public function prepareQuery(string $sql, array $params = [], string $types = ""): array {
        $stmt = $this->mysqli->prepare($sql);
        if (!$stmt) throw new Exception("準備失敗: " . $this->mysqli->error);
        
        if ($params) {
            $types = $types ?: str_repeat('s', count($params)); // 默認全字符串
            $stmt->bind_param($types, ...$params);
        }
        
        $stmt->execute();
        $res = $stmt->get_result();
        $data = $res ? $res->fetch_all(MYSQLI_ASSOC) : [];
        $stmt->close();
        return $data;
    }

    // 開啟事務
    public function beginTransaction(): void { $this->mysqli->begin_transaction(); }
    // 提交事務
    public function commit(): void { $this->mysqli->commit(); }
    // 回滾事務
    public function rollback(): void { $this->mysqli->rollback(); }

    public function __destruct() {
        if ($this->mysqli) $this->mysqli->close();
    }
}

// 使用示例
$helper = new SqlHelper();
$users = $helper->fetchAll("SELECT * FROM user1 WHERE age > ?", [18], "i");
foreach ($users as $u) {
    echo "{$u['name']} - {$u['email']}
"; } ?>

六、常見錯誤與最佳實踐

總結

mysqli 為 PHP 操作 MySQL 提供了強大、安全、現代化的接口。推薦使用面向對象風格配合預處理語句,並封裝通用的 SqlHelper 類簡化業務代碼。生產環境中結合連接池 (如 Swoole)、讀寫分離、緩存策略可進一步提升性能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題解決方案
中文亂碼連接後立即調用 set_charset("utf8mb4"),數據表也需 CHARSET=utf8mb4
SQL 注入絕不拼接變量,全部使用 預處理語句
連接洩漏使用構造/析構函數自動管理,或 try-finally 確保關閉
大結果集內存溢出使用 fetch_row() 逐行處理,或分頁 LIMIT,避免 fetch_all()
長連接問題PHP-FPM 模式下每請求一連接,無需持久連接;CLI 長運行腳本需定期重連