引言:
PHP 调用 MySQL 数据库主要通过 MySQLi 和 PDO_MySQL 两种扩展实现。本文系统讲解环境配置、连接管理、SQL 语句执行、预处理语句防护 SQL 注入、错误处理机制及 SSL 加密连接等核心内容,帮助 PHP 开发者安全高效地操作 MySQL 数据库。

PHP 的 MySQL 数据库调用完全指南

PHP 与 MySQL 是 Web 开发领域的经典组合,两者配合默契,共同支撑着无数动态网站和应用。在 PHP 中操作 MySQL 数据库,主要通过两种官方推荐的扩展来实现:MySQLiPDO_MySQL。本文将系统讲解从环境配置到连接操作,再到数据增删改查和安全实践的完整流程。

一、环境准备:安装必要组件

在开始之前,确保你的 PHP 环境已经安装了 MySQL 数据库和相应的 PHP 扩展。

Ubuntu/Debian 系统

1
2
3
4
5
6
# 安装 Apache、PHP、MySQL 及所需扩展
sudo apt update
sudo apt install apache2 mysql-server php php-mysql libapache2-mod-php

# 重启 Web 服务器
sudo systemctl restart apache2

验证扩展安装

1
php -m | grep -i mysql

正常输出应包含 mysqlipdo_mysql,表示扩展已成功安装。

二、两种主流连接方式

PHP 提供两种官方推荐的 MySQL 连接方式:MySQLi(MySQL Improved)和 PDO(PHP Data Objects)。两者各有优势,选择取决于具体需求。

方案一:MySQLi 扩展

MySQLi 是专门为 MySQL 设计的扩展,支持面向过程和面向对象两种编程风格。

特点

  • 支持 MySQL 特定的高级功能(如多语句执行、事务支持)
  • 提供面向过程和面向对象两种接口
  • 性能优秀,是 MySQL 专属的解决方案

示例:使用 MySQLi 面向对象方式连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$servername = "localhost";
$username = "your_username";
$password = "your_password";
$dbname = "your_database";

// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);

// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
echo "连接成功";

// 关闭连接
$conn->close();
?>

示例:使用 MySQLi 面向过程方式连接

1
2
3
4
5
6
7
8
9
10
<?php
$conn = mysqli_connect($servername, $username, $password, $dbname);

if (!$conn) {
die("连接失败: " . mysqli_connect_error());
}
echo "连接成功";

mysqli_close($conn);
?>

方案二:PDO_MySQL 扩展

PDO 是 PHP 提供的数据库抽象层,支持多种数据库系统(MySQL、PostgreSQL、SQLite 等),代码迁移性更好。

特点

  • 统一的 API 接口,可平滑切换数据库
  • 提供更好的异常处理机制(try-catch)
  • 支持命名参数,代码可读性更高
  • 是跨数据库项目的首选方案

示例:使用 PDO 连接 MySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$servername = "localhost";
$username = "your_username";
$password = "your_password";
$dbname = "your_database";

try {
$conn = new PDO(
"mysql:host=$servername;dbname=$dbname;charset=utf8mb4",
$username,
$password
);
// 设置错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "连接成功";
} catch(PDOException $e) {
echo "连接失败: " . $e->getMessage();
}

// 关闭连接
$conn = null;
?>

两种方式对比

特性 MySQLi PDO
数据库支持 仅 MySQL 支持 12+ 种数据库
编程风格 面向对象 + 面向过程 仅面向对象
预处理语句 支持 支持
命名参数 不支持 支持
异常处理 需手动配置 原生支持
适用场景 MySQL 专属项目 跨数据库项目

三、核心数据库操作

查询数据(SELECT)

MySQLi 查询示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}

$sql = "SELECT id, name, email FROM Users";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"] . " - Name: " . $row["name"] . " - Email: " . $row["email"] . "<br>";
}
} else {
echo "0 条结果";
}

$conn->close();
?>

PDO 查询示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$sql = "SELECT id, name, email FROM Users";
$stmt = $conn->query($sql);

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "ID: " . $row['id'] . " - Name: " . $row['name'] . " - Email: " . $row['email'] . "<br>";
}
} catch (PDOException $e) {
echo "查询失败: " . $e->getMessage();
}
?>

插入数据(INSERT)

使用 MySQLi 插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}

$sql = "INSERT INTO Users (name, email) VALUES ('张三', 'zhangsan@example.com')";

if ($conn->query($sql) === TRUE) {
echo "新记录插入成功,ID 为: " . $conn->insert_id;
} else {
echo "错误: " . $conn->error;
}

$conn->close();
?>

使用 PDO 插入数据

1
2
3
4
5
6
7
8
9
10
11
12
<?php
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$sql = "INSERT INTO Users (name, email) VALUES ('李四', 'lisi@example.com')";
$conn->exec($sql);
echo "新记录插入成功,ID 为: " . $conn->lastInsertId();
} catch (PDOException $e) {
echo "插入失败: " . $e->getMessage();
}
?>

更新数据(UPDATE)

1
2
3
4
5
6
7
8
9
10
11
12
<?php
// MySQLi 更新示例
$sql = "UPDATE Users SET email='newemail@example.com' WHERE id=1";
if ($conn->query($sql) === TRUE) {
echo "记录更新成功,影响行数: " . $conn->affected_rows;
}

// PDO 更新示例
$sql = "UPDATE Users SET email='newemail@example.com' WHERE id=1";
$rows = $conn->exec($sql);
echo "记录更新成功,影响行数: $rows";
?>

删除数据(DELETE)

1
2
3
4
5
6
7
8
9
10
11
12
<?php
// MySQLi 删除示例
$sql = "DELETE FROM Users WHERE id=1";
if ($conn->query($sql) === TRUE) {
echo "记录删除成功,影响行数: " . $conn->affected_rows;
}

// PDO 删除示例
$sql = "DELETE FROM Users WHERE id=1";
$rows = $conn->exec($sql);
echo "记录删除成功,影响行数: $rows";
?>

四、预处理语句与 SQL 注入防护

预处理语句(Prepared Statements)是防御 SQL 注入攻击的标准做法。

MySQLi 预处理语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}

// 创建预处理语句
$stmt = $conn->prepare("INSERT INTO Users (name, email) VALUES (?, ?)");
// 绑定参数:s 表示字符串类型,ss 表示两个字符串参数
$stmt->bind_param("ss", $name, $email);

// 设置参数并执行
$name = "王五";
$email = "wangwu@example.com";
$stmt->execute();

echo "新记录插入成功,ID 为: " . $stmt->insert_id;

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

PDO 预处理语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $conn->prepare("INSERT INTO Users (name, email) VALUES (:name, :email)");

$name = "赵六";
$email = "zhaoliu@example.com";
$stmt->execute([':name' => $name, ':email' => $email]);

echo "新记录插入成功,ID 为: " . $conn->lastInsertId();
} catch (PDOException $e) {
echo "插入失败: " . $e->getMessage();
}
?>

使用预处理语句查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// MySQLi 查询预处理
$stmt = $conn->prepare("SELECT id, name, email FROM Users WHERE id > ?");
$stmt->bind_param("i", $minId);
$minId = 2;
$stmt->execute();
$result = $stmt->get_result();

while ($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - Name: " . $row["name"] . " - Email: " . $row["email"] . "<br>";
}
$stmt->close();

// PDO 查询预处理
$stmt = $conn->prepare("SELECT id, name, email FROM Users WHERE id > :minId");
$stmt->execute([':minId' => 2]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "ID: " . $row['id'] . " - Name: " . $row['name'] . " - Email: " . $row['email'] . "<br>";
}
?>

五、错误处理与最佳实践

错误处理机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// MySQLi 错误处理
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}

$result = $conn->query($sql);
if (!$result) {
echo "查询错误: " . $conn->error;
}

// PDO 错误处理(异常模式)
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "连接失败: " . $e->getMessage();
}
?>

推荐的最佳实践

实践建议 说明
使用预处理语句 永远不要直接拼接用户输入到 SQL 中,使用预处理语句防止 SQL 注入
配置合适的字符集 使用 charset=utf8mb4 支持完整的 Unicode 和 Emoji 字符
密码不要硬编码 使用环境变量或配置文件存储数据库密码
生产环境关闭错误显示 使用 error_reporting(0) 避免暴露敏感信息
设置合理的连接超时 避免长时间等待无法响应的数据库连接
使用连接池或持久连接 减少频繁创建和销毁连接的开销

环境变量配置示例

1
2
3
4
5
6
7
<?php
// 从环境变量读取敏感信息
$host = getenv('DB_HOST') ?: 'localhost';
$dbname = getenv('DB_NAME') ?: 'myapp';
$user = getenv('DB_USER') ?: 'appuser';
$pass = getenv('DB_PASS') ?: '';
?>

六、SSL 加密连接

对于生产环境,建议使用 SSL/TLS 加密连接以保护数据传输安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
// MySQLi SSL 连接示例
$conn = mysqli_init();

mysqli_ssl_set(
$conn,
null,
null,
"/path/to/ca-cert.pem",
null,
null
);

mysqli_real_connect(
$conn,
$host,
$username,
$password,
$dbname,
3306,
MYSQLI_CLIENT_SSL
);

if (mysqli_connect_errno($conn)) {
die("SSL 连接失败: " . mysqli_connect_error());
}
?>

总结

PHP 与 MySQL 的配合使用是 Web 开发中的标准实践,核心要点可归纳为:

  1. 选择扩展:MySQLi 适合专属 MySQL 项目,PDO 适合跨数据库或需要更高抽象层的情况
  2. 安全第一:始终使用预处理语句防止 SQL 注入,合理配置字符集和错误处理
  3. 连接配置:密码避免硬编码,生产环境使用 SSL 加密连接

掌握这些基础操作后,就可以进一步学习事务处理、存储过程调用、批量操作等高级特性,构建出更强大、安全的 Web 应用。