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']}
";
}
?>
六、常見錯誤與最佳實踐
| 問題 | 解決方案 |
| 中文亂碼 | 連接後立即調用 set_charset("utf8mb4"),數據表也需 CHARSET=utf8mb4 |
| SQL 注入 | 絕不拼接變量,全部使用 預處理語句 |
| 連接洩漏 | 使用構造/析構函數自動管理,或 try-finally 確保關閉 |
| 大結果集內存溢出 | 使用 fetch_row() 逐行處理,或分頁 LIMIT,避免 fetch_all() |
| 長連接問題 | PHP-FPM 模式下每請求一連接,無需持久連接;CLI 長運行腳本需定期重連 |
總結
mysqli 為 PHP 操作 MySQL 提供了強大、安全、現代化的接口。推薦使用面向對象風格配合預處理語句,並封裝通用的 SqlHelper 類簡化業務代碼。生產環境中結合連接池 (如 Swoole)、讀寫分離、緩存策略可進一步提升性能。
- 上一篇文章: PHP GD 庫繪圖技術詳解:從畫布創建到圖形繪製與中文輸出
- 下一篇文章: PHP 文件上傳完整實戰:從表單構建到安全處理與 OOP 封裝
Copyright ©
程式碼之家 All Rights Reserved