| SQL 類型 | 成功返回 | 失敗返回 | 說明 |
|---|---|---|---|
| SELECT / SHOW / DESCRIBE / EXPLAIN | Resource (結果集句柄) | FALSE | 需配合 mysql_fetch_assoc() 等獲取數據 |
| INSERT / UPDATE / DELETE / REPLACE | TRUE | FALSE | 影響行數用 mysql_affected_rows() 獲取 |
| CREATE / DROP / ALTER / TRUNCATE | TRUE | FALSE | DDL 操作 |
0) {
$row = mysql_fetch_assoc($result);
echo "找到用戶: {$row['name']}";
} else {
echo "用戶不存在";
}
// ❌ 錯誤:INSERT 判斷影響行數
$sql = "INSERT INTO users (name) VALUES ('test')";
if (mysql_query($sql)) { // 只能知道語法/執行是否成功
echo "插入成功"; // 即使主鍵衝突 IGNORE 也返回 TRUE
}
// ✅ 正確:檢查影響行數
mysql_query($sql);
if (mysql_affected_rows() > 0) {
echo "插入成功,ID: " . mysql_insert_id();
} else {
echo "插入失敗或無變化: " . mysql_error();
}
?>
resource mysql_query ( string $query [, resource $link_identifier = NULL ] )
參數:
query - SQL 語句 (不以分號結尾)
link_identifier - 可選,mysql_connect() 返回的連接資源,省略則用最後打開的連接
返回:
SELECT 類: resource | FALSE
其他: TRUE | FALSE
";
}
// 3. 釋放結果集 (長腳本必做)
mysql_free_result($result);
// 4. 獲取插入 ID
mysql_query("INSERT INTO logs (msg) VALUES ('test')", $link);
$new_id = mysql_insert_id($link);
// 5. 獲取影響行數
$affected = mysql_affected_rows($link);
// 6. 關閉連接
mysql_close($link);
?>
現有項目 必須遷移 到 mysqli 或 PDO。
";
}
mysqli_free_result($result);
// 寫入
mysqli_query($mysqli, "INSERT INTO logs (msg) VALUES ('test')");
$new_id = mysqli_insert_id($mysqli);
$affected = mysqli_affected_rows($mysqli);
// 關閉
mysqli_close($mysqli);
?>
connect_errno) {
die('連接失敗: ' . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');
// 預處理語句 (防注入、性能更好)
$stmt = $mysqli->prepare("SELECT id, name, email FROM users WHERE status = ? AND created_at > ?");
$stmt->bind_param('is', $status, $date);
$status = 1;
$date = '2024-01-01';
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo "{$row['id']}: {$row['name']} <{$row['email']}>
";
}
$result->free();
$stmt->close();
// 事務
$mysqli->begin_transaction();
try {
$mysqli->query("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$mysqli->query("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$mysqli->commit();
} catch (Exception $e) {
$mysqli->rollback();
throw $e;
}
$mysqli->close();
?>
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 使用真實預處理
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
$pdo = new PDO($dsn, 'user', 'pass', $options);
// 查詢
$stmt = $pdo->prepare("SELECT id, name FROM users WHERE status = ?");
$stmt->execute([1]);
foreach ($stmt as $row) {
echo "{$row['id']}: {$row['name']}
";
}
// 寫入 + 事務
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("INSERT INTO logs (msg, level) VALUES (?, ?)");
$stmt->execute(['User login', 'INFO']);
$log_id = $pdo->lastInsertId();
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
?>
| 特性 | mysql (已移除) | mysqli (過程/對象) | PDO |
|---|---|---|---|
| PHP 版本支持 | ≤ 5.6 | 5.0+ | 5.1+ |
| 預處理語句 | ❌ | ✅ | ✅ |
| 事務控制 | 手動 SQL | API + SQL | API (統一接口) |
| 多數據庫支持 | ❌ | ❌ 只支持 MySQL | ✅ 12+ 驅動 |
| 異步查詢 | ❌ | ✅ (mysqli_poll) | ❌ |
| 學習曲線 | 低 | 低 (過程式) | 中 |
| 推薦場景 | 不推薦 | 純 MySQL 專案、遷移舊代碼 | 新項目、多數據庫、框架開發 |
# 1. Rector (自動重構 PHP 代碼)
composer require rector/rector --dev
vendor/bin/rector process src --config rector.php
# rector.php
use Rector\Set\ValueObject\SetList;
use Rector\Config\RectorConfig;
return static function (RectorConfig $config) {
$config->sets([SetList::MYSQL_TO_MYSQLI]);
};
# 2. 手動查找替換 (IDE 正則)
# mysql_query\( → mysqli_query($link,
# mysql_fetch_assoc\( → mysqli_fetch_assoc(
# mysql_error\(\) → mysqli_error($link)
# mysql_connect\( → mysqli_connect(
行動建議:立即停止使用 mysql_* 函數。新項目直接用 PDO;存量項目用 Rector 自動遷移至 mysqli 面向對象風格,配合預處理語句徹底根治 SQL 注入風險。