雖然現代框架多封裝了 ORM/Query Builder,但理解原生 mysqli/PDO 操作對排錯、效能調優、舊專案維護仍至關重要。本文提供一份完整、安全、可直接落地的 MySQL 基礎操作範本,已棄用 老舊 mysql_* 函式,改用 mysqli 面向物件風格並採用預處理語句防止 SQL 注入。
<?php
// config/db.php
return [
'host' => 'localhost',
'username' => 'db_user',
'password' => 'secure_password_123',
'database' => 'products',
'charset' => 'utf8mb4',
'port' => 3306,
];
<?php
require_once 'config/db.php';
$cfg = require 'config/db.php';
$mysqli = new mysqli($cfg['host'], $cfg['username'], $cfg['password'], $cfg['database'], $cfg['port']);
if ($mysqli->connect_errno) {
// 生產環境請記錄日誌而非直接輸出
error_log("MySQL 連線失敗: {$mysqli->connect_error}");
exit('資料庫連線失敗,請稍後再試');
}
$mysqli->set_charset($cfg['charset']);
// 開啟異常模式(PHP 8.1+ 預設開啟),方便 try-catch 捕獲
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// 單筆查詢
$stmt = $mysqli->prepare("SELECT id, name, price FROM `category` WHERE id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
// 列表查詢
$stmt = $mysqli->prepare("SELECT id, name FROM `category` ORDER BY id DESC LIMIT ?, ?");
$stmt->bind_param('ii', $offset, $limit);
$stmt->execute();
$list = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
$name = '新分類';
$stmt = $mysqli->prepare("INSERT INTO `category` (`name`) VALUES (?)");
$stmt->bind_param('s', $name);
$stmt->execute();
if ($stmt->affected_rows > 0) {
$insertId = $stmt->insert_id; // 獲取自增 ID
echo "新增成功,ID: $insertId";
} else {
echo "新增失敗";
}
$id = 5;
$newName = '更新後名稱';
$stmt = $mysqli->prepare("UPDATE `category` SET `name` = ? WHERE `id` = ?");
$stmt->bind_param('si', $newName, $id);
$stmt->execute();
echo $stmt->affected_rows > 0 ? '修改成功' : '修改失敗或數據無變化';
$id = 5;
$stmt = $mysqli->prepare("DELETE FROM `category` WHERE `id` = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
echo $stmt->affected_rows > 0 ? '刪除成功' : '刪除失敗或記錄不存在';
$stmt->close();
$mysqli->close();
$mysqli->begin_transaction();
try {
$stmt1 = $mysqli->prepare("UPDATE `account` SET balance = balance - ? WHERE id = ?");
$stmt1->bind_param('di', 100, 1);
$stmt1->execute();
$stmt2 = $mysqli->prepare("UPDATE `account` SET balance = balance + ? WHERE id = ?");
$stmt2->bind_param('di', 100, 2);
$stmt2->execute();
$mysqli->commit();
} catch (Exception $e) {
$mysqli->rollback();
error_log("轉賬失敗: {$e->getMessage()}");
}
$data = [['name' => 'A'], ['name' => 'B'], ['name' => 'C']];
$placeholders = implode(',', array_fill(0, count($data), '(?)'));
$sql = "INSERT INTO `category` (`name`) VALUES $placeholders";
$stmt = $mysqli->prepare($sql);
// 動態綁定參數
$types = str_repeat('s', count($data));
$names = array_column($data, 'name');
$stmt->bind_param($types, ...$names);
$stmt->execute();
? 佔位符。mysqli::real_escape_string 轉義後拼接(極少數場景)。| 舊函式 | mysqli 替代 | 備註 |
|---|---|---|
| mysql_connect | new mysqli() | 面向物件風格 |
| mysql_query | $mysqli->prepare()->execute() | 預處理語句 |
| mysql_fetch_array | $result->fetch_assoc() | 返回關聯陣列 |
| mysql_insert_id | $stmt->insert_id | |
| mysql_affected_rows | $stmt->affected_rows | |
| mysql_error | $mysqli->error / $stmt->error | |
| mysql_close | $mysqli->close() |
採用 mysqli + 預處理語句是 PHP 操作 MySQL 的現代基準。本文提供的範本涵蓋連線管理、CRUD、事務、批量操作等核心場景,並強調安全與錯誤處理規範。建議新專案直接使用 PDO(支援多資料庫)或成熟 ORM(如 Eloquent、Doctrine),但在理解底層原理、維護舊系統、編寫高效能原生查詢時,本指南仍具備極高參考價值。