PHP 基础案例教程之 07-PHP 操作 MySQL 数据库
AI 摘要
PHP 操作数据库
PHP 中的数据库扩展
在 PHP 应用中要和 MySQL 数据库进行交互,需要借助 PHP 提供的数据库扩展。
- MySQL 扩展:PHP 与 MySQL 数据库交互的早期扩展,在 PHP 7 中已经彻底被淘汰。
- MySQLi 扩展:专为 MySQL 设计,是 MySQL 扩展的增强版,包含所有 MySQL 扩展的功能函数和 MySQL 高级特性。
- PDO 扩展:解决了早期 PHP 中不同数据库扩展的 API 接口互不兼容的问题,是现代 PHP 框架和需要跨数据库的应用首选。
MySQLi
MySQLi 概述
MySQLi 扩展提供了大量的函数操作 MySQL,使得在 PHP 程序中操作数据库变得轻松便捷。
MySQLi 扩展默认已经安装,在使用时需要在 PHP 配置文件(php.ini)中开启。
PHP 配置文件(php.ini):
extension=mysqliMySQLi 函数
MySQLi 扩展不仅为 PHP 连接数据库、执行 SQL 语句提供了函数,而且提供了很多简化开发的其他常用操作函数。
MySQLi 扩展的基本函数:
| 名称 | 描述 |
|---|---|
| mysqli_connect() | 连接 MySQL 服务器 |
| mysqli_connect_error() | 获取连接服务器时的错误信息 |
| mysqli_select_db() | 选择数据库 |
| mysqli_set_charset() | 设置客户端字符集 |
| mysqli_query() | 执行 SQL 语句 |
| mysqli_insert_id() | 获取上一次插入操作时产生的 id |
| mysqli_affected_rows() | 获取上一次操作时受影响的行数 |
| mysqli_errno() | 返回上一个 MySQL 操作中的错误信息的错误码 |
| mysqli_error() | 返回上一个 MySQL 操作产生的错误信息 |
| mysqli_close() | 关闭数据库连接 |
连接数据库
PHP 访问 MySQL 数据库之前,需要连接数据库。
mysqli_connect 函数的基本用法:
$数据库连接对象 = mysqli_connect(主机地址, 用户名, 密码, 数据库名, 主机端口号);在使用 PHP 连接数据库时,还需要设置字符集,确保 PHP 与 MySQL 的连接使用相同的字符集 UTF8。
mysqli_set_charset 函数的基本用法:
mysqli_set_charset(数据库连接对象, 字符集编码);MySQL 连接成功后,执行完操作,需要在适当的时候关闭数据库连接。
mysqli_close 函数的基本用法:
mysqli_close(数据库连接对象);示例:连接数据库
SQL 脚本:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
`orderId` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '订单编号',
`productName` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '产品名称',
`price` decimal(10,2) DEFAULT NULL COMMENT '产品价格',
`userName` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '买家姓名',
`phone` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '买家电话',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of order
-- ----------------------------
BEGIN;
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (1, 'No.001', '智能手机', 14999.00, '张三', '13888888888');
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (2, 'No.002', '笔记本电脑', 8999.00, '李四', '15788888888');
INSERT INTO `order` (`id`, `orderId`, `productName`, `price`, `userName`, `phone`) VALUES (3, 'No.003', '无线蓝牙耳机', 129.00, '王五', '18988888888');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;入口页面(index.php):
<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");
if(!$mysql) {
// 连接失败,输出错误信息
exit(mysqli_error($mysql));
}
// 设置字符集编码
mysqli_set_charset($mysql, "utf8");
print_r("数据库连接成功");
// 关闭数据库连接
mysqli_close($mysql);示例效果:
执行 SQL 语句
数据库连接成功后,就可以执行 SQL 语句进行数据操作。
mysqli_query 函数的基本用法:
mysqli_query(数据库连接对象, SQL语句, 结果集模式);当函数执行写操作时,函数返回值为 boolean。
当函数执行读操作时,函数根据结果集模式返回查询结果集。
- MYSQLI_STORE_RESULT:默认模式,会将结果集全部读取到 PHP。
- MYSQLI_USE_RESULT:仅初始化结果集检索,在处理结果集时进行数据读取。
处理结果集
使用 mysqli_query 函数执行读操作时,返回的是一个资源类型的结果集,需要对结果集作进一步处理,获取结果集中的数据。
MySQLi 扩展处理结果集的基本函数:
| 名称 | 描述 |
|---|---|
| mysqli_num_rows(结果集对象) | 获取结果中行的数量 |
| mysqli_fetch_all(结果集对象, 数组形式) | 获取所有结果并以数组方式返回 数组形式:MYSQL_ASSOC(关联数组)/ MYSQL_NUM(索引数组) |
| mysqli_fetch_array(结果集对象) | 获取一行结果并以数组方式返回 |
| mysqli_fetch_assoc(结果集对象) | 获取一行结果并以关联数组返回 |
| mysqli_fetch_row(结果集对象) | 获取一行结果并以索引数组返回 |
| mysqli_free_result(结果集对象) | 释放结果集 |
示例:处理结果集
入口页面(index.php):
<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");
if(!$mysql) {
// 连接失败,输出错误信息
exit(mysqli_error($mysql));
}
// 设置字符集编码
mysqli_set_charset($mysql, "utf8");
print_r("数据库连接成功");
// 执行SQL语句
$result = mysqli_query($mysql, "SELECT * FROM `order`");
// 获取结果集数组
print_r("<pre>");
print_r(mysqli_fetch_all($result, MYSQLI_ASSOC));
print_r("</pre>");
// 关闭数据库连接
mysqli_close($mysql);示例效果:
预处理操作
使用 MySQLi 扩展执行增删改操作时,需要拼接 SQL 语句,效率低,安全性差,容易导致 SQL 注入问题。
MySQLi 扩展预处理提供了预处理方式,实现 SQL 语句和数据的分离,执行 SQL 语句运行效率高,无须考虑数据中包含特殊字符导致的 SQL 注入问题。
预处理的实现过程:
- 定义一个 SQL 语句模板。
- 为该模板进行参数绑定。
- 将用户提交的数据内容发送给 MySQL 执行。
mysqli_prepare 函数用于预处理 SQL 模板,在编写 SQL 模板时,使用 ? 号占位符代替数据部分,且占位符两边无须使用引号包裹。
mysqli_prepare 函数的基本用法:
$预处理对象 = mysqli_prepare(数据库连接对象, SQL模板);mysqli_stmt_bind_param 函数用于将变量作为参数绑定到预处理语句中。
mysqli_stmt_bind_param 函数的基本用法:
mysqli_stmt_bind_param(预处理对象, 数据类型, 绑定变量1, 绑定变量2...);使用 mysqli_stmt_bind_param 函数进行参数绑定时,可以指定数据类型,且与绑定变量一一对应,绑定变量使用引用传参。
参数绑定时可以指定的基本数据类型:
| 名称 | 描述 |
|---|---|
| i | 整型 |
| d | 浮点型 |
| s | 字符串型 |
| b | 二进制对象 |
mysqli_stmt_execute 函数用于执行预处理语句。
mysqli_stmt_execute 函数的基本用法:
mysqli_stmt_execute(预处理对象);示例:预处理操作
入口页面(index.php):
<?php
// 连接数据库
$mysql = mysqli_connect("localhost", "root", "123456..", "demo", "3306");
if(!$mysql) {
// 连接失败,输出错误信息
exit(mysqli_error($mysql));
}
// 设置字符集编码
mysqli_set_charset($mysql, "utf8");
print_r("数据库连接成功");
// 定义预处理对象
$stmt = mysqli_prepare($mysql, "UPDATE `order` SET productName = ?, price = ? WHERE id = ?");
// 绑定参数
$productName = "HUAWEI手机";
$price = 7999.0;
$id = 1;
mysqli_stmt_bind_param($stmt, "sdi", $productName, $price, $id);
// 执行预处理语句
$result = mysqli_stmt_execute($stmt);
print_r($result ? "执行成功" : "执行失败");
// 关闭数据库连接
mysqli_close($mysql);示例效果:
PDO
PDO 概述
PDO(PHP Data Objects)是 PHP 官方提供的数据库抽象层扩展,从 PHP 5.1 开始内置支持,PHP 7/8 成为操作数据库的主流标准,也是所有主流 PHP 框架(如 Laravel、ThinkPHP、Yii 等)的底层数据库驱动。
PDO 是一套统一的数据库操作接口,封装了不同数据库的底层实现差异,让开发者能用同一套代码语法操作 MySQL、PostgreSQL、SQLite、Oracle 等几十种数据库,同时提供了完善的防 SQL 注入方案,是现代 PHP 开发中操作数据库的首选方案。
PDO 与 mysqli、mysqli 对比:
| 特性 | PDO | mysqli | mysql |
|---|---|---|---|
| 支持数据库 | 跨库兼容 | 仅 MySQL/MariaDB | 仅 MySQL/MariaDB |
| 防注入支持 | 原生预处理(推荐) | 原生预处理(仅问号占位) | 无,需手动转义 |
| 占位符类型 | 命名占位符 + 问号占位符 | 仅问号占位符 | 无占位符,需拼接 SQL |
| 错误处理 | 支持异常抛出,高效 | 需手动判断,繁琐 | 需手动判断,繁琐 |
| 语法风格 | 统一面向对象语法 | 面向对象 + 过程化(双套) | 仅过程化语法 |
PHP 7/8 已默认启用 PDO,无需额外安装,如未默认启用,需要在 PHP 配置文件(php.ini)中开启。
PHP 配置文件(php.ini):
extension=pdo_mysql连接数据库
PDO 通过构造函数创建连接对象。
PDO 构造函数的基本用法:
// 构建 DSN
$dsn = "mysql:host=主机地址:主机端口号;dbname=数据库名;charset=编码";
// 构建 PDO核心配置项
$options = [
// 错误时抛出异常,替代手动判断
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// 关闭模拟预处理,使用MySQL原生预处理,防SQL注入核心
PDO::ATTR_EMULATE_PREPARES => false,
// 默认返回关联数组
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
// 构建 PDO
$pdo = new PDO($dsn, 用户名, 密码, $options);
} catch (PDOException $e) {
// 捕获异常
die("数据库连接失败:".$e->getMessage());
}示例:连接数据库
入口页面(index.php):
<?php
$dsn = "mysql:host=localhost:3306;dbname=demo;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, "root", "123456..", $options);
echo "数据库连接成功";
} catch (PDOException $e) {
die("数据库连接失败:".$e->getMessage());
}示例效果:
预处理操作
PDO 执行 SQL 分两种场景:
- 所有带动态参数的 SQL(如用户输入、变量),必须用「预处理语句」,这是防 SQL 注入的唯一有效方式。
- 无参数的固定 SQL(如查所有数据),可直接执行。
预处理语句分为 prepare 预处理 和 execute 执行两步:
- 先将带占位符的 SQL 发送给 MySQL 编译,编译后可重复执行。
- 再将参数值发送给 MySQL,参数值会被当作纯数据处理,不会被解析为 SQL 语句,从根本上避免注入。
PDO 支持两种占位符:
- 命名占位符::变量名(如:id、:name),执行时用关联数组传参,推荐使用命名占位符。
- 问号占位符:?,执行时用索引数组传参,参数顺序必须和 SQL 中一致。
预处理操作的基本用法:
// 定义带命名占位符的SQL(字段名和占位符对应)
$sql = "INSERT INTO user (name, age, email) VALUES (:name, :age, :email)";
// prepare 预处理
$stmt = $pdo->prepare($sql);
// 定义参数数组(键=占位符,值=实际数据)
$params = [
':name' => '张三',
':age' => 20,
':email' => 'zhangsan@test.com'
];
// execute 执行
$stmt->execute($params);CRUD
PDO CRUD 中的基本函数:
| 名称 | 描述 |
|---|---|
| lastInsertId() | 获取新增数据的自增 ID |
| fetch() | 获取单条数据,适用于按 ID 查、查一条记录 |
| fetchAll() | 获取所有数据,适用于查列表、多条记录 |
| rowCount() | 获取查询结果的行数 增删改时返回操作影响的行数 |
PDO 操作数据库的核心流程:
- 创建 PDO 连接对象:配置数据库地址、库名、账号密码及核心参数,建立与数据库的连接。PDO 对象全局唯一,一个项目只需一个连接,可设计为单例。
- 预处理 SQL 语句:通过 prepare 函数编译带占位符的 SQL,返回语句对象。
- 执行并传参:通过 execute 函数传递参数,执行预处理后的 SQL。
- 获取执行结果:通过 CRUD 基本半数获取执行结果。
示例:CRUD
入口页面(index.php):
<?php
$dsn = "mysql:host=localhost:3306;dbname=demo;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, "root", "123456..", $options);
echo "数据库连接成功";
} catch (PDOException $e) {
die("数据库连接失败:".$e->getMessage());
}
// 新增数据
echo "【新增数据】<br>";
$insertSql = "INSERT INTO `order` (orderId, productName, price, userName, phone) VALUES (:orderId, :productName, :price, :userName, :phone)";
$insertStmt = $pdo->prepare($insertSql);
$insertStmt->execute([
':orderId' => 'No.004',
':productName' => '华为Mate80 Pro',
':price' => 9999.00,
':userName' => '张三',
':phone' => '13800138000'
]);
$newOrderId = $pdo->lastInsertId();
echo "新增成功!自增ID:{$newOrderId}<br><hr>";
// 查询数据
echo "【查询数据】<br>";
$listSql = "SELECT id, orderId, productName, price, userName FROM `order` ORDER BY id DESC";
$listStmt = $pdo->query($listSql);
$orderList = $listStmt->fetchAll();
echo "所有数据(共{$listStmt->rowCount()}条):<br>";
foreach ($orderList as $item) {
echo "ID:{$item['id']} | 订单号:{$item['orderId']} | 商品:{$item['productName']} | 价格:{$item['price']}元<br>";
}
echo "<hr>";
// 修改数据
echo "【修改数据】<br>";
$updateSql = "UPDATE `order` SET productName = :productName, price = :price, phone = :phone WHERE id = :id";
$updateStmt = $pdo->prepare($updateSql);
$updateStmt->execute([
':productName' => '华为Mate60 Pro+',
':price' => 7999.00,
':phone' => '13900139000',
':id' => $newOrderId
]);
$updateRow = $updateStmt->rowCount();
if ($updateRow > 0) {
echo "修改成功!共修改{$updateRow}条数据<br>";
} else {
echo "修改失败<br>";
}
echo "<hr>";
echo "【删除数据】<br>";
$deleteSql = "DELETE FROM `order` WHERE id = :id";
$deleteStmt = $pdo->prepare($deleteSql);
$deleteStmt->execute([':id' => 1]);
$deleteRow = $deleteStmt->rowCount();
if ($deleteRow > 0) {
echo "删除成功!已删除ID为{$newOrderId}的数据<br>";
} else {
echo "删除失败<br>";
}示例效果:
文章中可能会存在些许错别字内容描述不完整、表述不准确、排版布局异常等问题,文章中提及的软件、依赖、框架等程序可能随其版本更新迭代而产生变化,文章中的相关代码片段、例图、文本等内容仅供参考。
如若转载,请注明出处:https://www.duox.dev/post/178.html
- 上一篇:PHP 基础案例教程之 06-Web 前后端数据交互
- 下一篇:没有了