当前位置:首页 > 学海无涯 > 正文内容

PHP 链接数据库与基础增删改查(CRUD)操作详解

清羽天2周前 (11-27)学海无涯13


在 Web 开发中,PHP 与数据库的交互是动态网站的核心能力 —— 无论是用户登录注册、数据展示还是业务逻辑处理,都离不开 PHP 对数据库的增删改查操作。本文将以 MySQL 数据库(PHP 生态最常用的关系型数据库)为例,从环境准备、数据库连接、核心 CRUD 实现到安全优化,一步步带大家掌握 PHP 操作数据库的基础技能,适合新手入门学习。

一、环境准备

在编码前,需确保 “运行环境 + 数据库 + 依赖” 全部就绪,避免后续出现兼容性问题。

1.1 核心环境与工具

  • PHP 环境:推荐 PHP 7.4+ 版本(本文使用 PHP 8.1,兼容 MySQL 8.0+,性能更优)。

  • MySQL 数据库:推荐 MySQL 8.0 或 MariaDB 10.5+,需提前创建测试库和表。

  • 开发工具:Visual Studio Code(配 PHP 插件)、PhpStorm,或简易编辑器如 Sublime Text。

  • 运行服务器:XAMPP、WAMP(集成 Apache + PHP + MySQL,新手首选),或独立配置 Nginx + PHP-FPM。

  • 数据库管理工具:Navicat、SQLyog 或 PHPMyAdmin(XAMPP 自带),用于执行 SQL 语句和管理数据。

1.2 环境验证

  1. 启动 PHP 运行环境(如 XAMPP 启动 Apache 和 MySQL)。

  2. 在网站根目录(如 XAMPP 的 htdocs 文件夹)创建 phpinfo.php,内容如下:

    php
    运行
    <?phpphpinfo(); // 输出 PHP 环境信息?>
  3. 浏览器访问 http://localhost/phpinfo.php,搜索 mysqli 或 PDO,确认扩展已启用(默认 PHP 7+ 已内置,无需额外安装)。

1.3 测试数据库与表创建

打开 MySQL 客户端(如 PHPMyAdmin、Navicat),执行以下 SQL 语句,创建测试用的数据库 php_db 和用户表 users
sql
-- 1. 创建数据库(若不存在),指定 UTF-8 编码CREATE DATABASE IF NOT EXISTS php_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 2. 使用数据库USE php_db;-- 3. 创建用户表(存储用户ID、姓名、年龄、邮箱、注册时间)CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主键自增
    name VARCHAR(50) NOT NULL,         -- 姓名,非空
    age TINYINT UNSIGNED,              -- 年龄,无符号(0-255)
    email VARCHAR(100) UNIQUE NOT NULL,-- 邮箱,唯一且非空
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP -- 注册时间,默认当前时间) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、PHP 链接数据库的两种核心方式

PHP 提供两种主流数据库连接方式:MySQLi(MySQL 改进版扩展,仅支持 MySQL)和 PDO(PHP Data Objects,支持多数据库如 MySQL、PostgreSQL 等)。本文重点讲解 PDO(通用性强、支持预处理防 SQL 注入,推荐生产环境使用),同时补充 MySQLi 基础用法作为对比。

2.1 核心连接参数

无论哪种方式,都需要以下 4 个核心参数:
  • 数据库地址:localhost(本地)或远程服务器 IP。

  • 端口号:MySQL 默认 3306(若未修改)。

  • 数据库名:php_db(上文创建的测试库)。

  • 用户名 / 密码:你的 MySQL 登录信息(如 root/123456)。

2.2 PDO 连接方式(推荐)

PDO 是 PHP 官方推荐的数据库操作扩展,支持事务、预处理语句,兼容性更强。以下是 PDO 工具类封装(统一管理连接与关闭,避免代码冗余):
php
运行
<?php/**
 * PDO 数据库工具类:封装连接、关闭、异常处理
 */class PDODB {
    // 数据库连接参数(实际开发建议放在配置文件中)
    private static $host = 'localhost';
    private static $dbname = 'php_db';
    private static $username = 'root';
    private static $password = '123456';
    private static $charset = 'utf8mb4';
    private static $dsn; // 数据源名称(PDO 连接格式)
    private static $pdo = null; // PDO 实例(单例模式,避免重复创建连接)

    /**
     * 初始化连接(单例模式)
     * @return PDO 连接实例
     * @throws PDOException 连接异常
     */
    public static function getConnection() {
        // 若已创建连接,直接返回
        if (self::$pdo !== null) {
            return self::$pdo;
        }

        // 构建 DSN(PDO 连接格式:mysql:host=xxx;dbname=xxx;charset=xxx)
        self::$dsn = "mysql:host=" . self::$host . ";dbname=" . self::$dbname . ";charset=" . self::$charset;

        try {
            // 创建 PDO 实例(开启异常模式,便于捕获错误)
            self::$pdo = new PDO(
                self::$dsn,
                self::$username,
                self::$password,
                [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 抛出异常
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // 默认以关联数组返回结果
                ]
            );
            echo "PDO 数据库连接成功!<br>";
            return self::$pdo;
        } catch (PDOException $e) {
            // 连接失败,抛出异常(实际开发可记录日志)
            die("PDO 连接失败:" . $e->getMessage());
        }
    }

    /**
     * 关闭连接(PDO 会自动关闭,手动关闭仅作演示)
     */
    public static function closeConnection() {
        self::$pdo = null;
        echo "PDO 连接已关闭!<br>";
    }}
关键说明:
  • ERRMODE_EXCEPTION:开启异常模式,后续 SQL 错误会抛出异常,便于统一处理。

  • FETCH_ASSOC:默认以关联数组返回查询结果(如 ['id' => 1, 'name' => '张三']),使用更直观。

  • 单例模式:避免重复创建数据库连接,减少服务器资源消耗。

2.3 MySQLi 连接方式(补充)

MySQLi 分为 “面向对象” 和 “面向过程” 两种风格,以下是面向对象的基础连接示例(仅作对比,推荐优先使用 PDO):
php
运行
<?php// MySQLi 面向对象连接$host = 'localhost';$dbname = 'php_db';$username = 'root';$password = '123456';// 创建 MySQLi 实例$mysqli = new mysqli($host, $username, $password, $dbname);// 检查连接错误if ($mysqli->connect_error) {
    die("MySQLi 连接失败:" . $mysqli->connect_error);}// 设置字符编码$mysqli->set_charset('utf8mb4');echo "MySQLi 连接成功!<br>";// 关闭连接$mysqli->close();echo "MySQLi 连接已关闭!<br>";

三、基础增删改查(CRUD)操作实现

以下基于 PDO 工具类 实现 users 表的 CRUD 操作,核心使用 PDO::prepare() 预处理语句(防 SQL 注入,生产环境必备)。

3.1 新增操作(Create)

功能:向 users 表插入一条新用户数据。
php
运行
<?phprequire_once 'PDODB.php'; // 引入 PDO 工具类try {
    // 1. 获取数据库连接
    $pdo = PDODB::getConnection();

    // 2. 定义 SQL(:name 为命名占位符,也可使用 ? 问号占位符)
    $sql = "INSERT INTO users (name, age, email) VALUES (:name, :age, :email)";

    // 3. 预处理 SQL(编译 SQL,避免重复解析,提升性能)
    $stmt = $pdo->prepare($sql);

    // 4. 绑定参数并执行(两种方式可选)
    // 方式1:数组绑定(推荐,简洁)
    $userData = [
        ':name' => '张三',
        ':age' => 24,
        ':email' => 'zhangsan@example.com'
    ];
    $stmt->execute($userData);

    // 方式2:逐个绑定(适合需要指定参数类型的场景)
    // $stmt->bindParam(':name', $name, PDO::PARAM_STR);
    // $stmt->bindParam(':age', $age, PDO::PARAM_INT);
    // $stmt->execute();

    // 获取新增数据的自增 ID
    $newUserId = $pdo->lastInsertId();
    echo "新增用户成功!用户ID:" . $newUserId . "<br>";} catch (PDOException $e) {
    echo "新增失败:" . $e->getMessage() . "<br>";} finally {
    // 关闭连接(可选,PDO 脚本结束会自动关闭)
    PDODB::closeConnection();}

3.2 查询操作(Read)

查询分为 “查询单条数据” 和 “查询多条数据”,核心通过 fetch()(单条)或 fetchAll()(多条)处理结果集。

3.2.1 查询单条数据(按 ID 查询)

php
运行
<?phprequire_once 'PDODB.php';try {
    $pdo = PDODB::getConnection();
    $targetId = 1; // 要查询的用户ID

    // 预处理查询 SQL
    $sql = "SELECT id, name, age, email, create_time FROM users WHERE id = :id";
    $stmt = $pdo->prepare($sql);

    // 执行查询(绑定参数)
    $stmt->execute([':id' => $targetId]);

    // 获取单条结果(关联数组格式)
    $user = $stmt->fetch();

    if ($user) {
        echo "查询到用户:<br>";
        echo "ID:" . $user['id'] . "<br>";
        echo "姓名:" . $user['name'] . "<br>";
        echo "年龄:" . $user['age'] . "<br>";
        echo "邮箱:" . $user['email'] . "<br>";
        echo "注册时间:" . $user['create_time'] . "<br>";
    } else {
        echo "未查询到 ID 为 " . $targetId . " 的用户<br>";
    }} catch (PDOException $e) {
    echo "查询失败:" . $e->getMessage() . "<br>";} finally {
    PDODB::closeConnection();}

3.2.2 查询多条数据(查询所有用户)

只需修改 SQL 和结果集处理方式,使用 fetchAll() 获取所有数据:
php
运行
<?phprequire_once 'PDODB.php';try {
    $pdo = PDODB::getConnection();

    // 查询所有用户(按注册时间倒序)
    $sql = "SELECT id, name, age, email FROM users ORDER BY create_time DESC";
    $stmt = $pdo->prepare($sql);
    $stmt->execute();

    // 获取所有结果(关联数组集合)
    $users = $stmt->fetchAll();

    if (count($users) > 0) {
        echo "所有用户列表:<br>";
        foreach ($users as $index => $user) {
            echo "序号 " . ($index + 1) . ":";
            echo "ID=" . $user['id'] . ",姓名=" . $user['name'] . ",邮箱=" . $user['email'] . "<br>";
        }
    } else {
        echo "暂无用户数据<br>";
    }} catch (PDOException $e) {
    echo "查询失败:" . $e->getMessage() . "<br>";} finally {
    PDODB::closeConnection();}

3.3 修改操作(Update)

功能:根据用户 ID 修改姓名、年龄或邮箱。
php
运行
<?phprequire_once 'PDODB.php';try {
    $pdo = PDODB::getConnection();
    $userId = 1; // 要修改的用户ID

    // 定义修改 SQL
    $sql = "UPDATE users SET name = :name, age = :age WHERE id = :id";
    $stmt = $pdo->prepare($sql);

    // 绑定参数并执行
    $updateData = [
        ':name' => '张三_更新',
        ':age' => 25,
        ':id' => $userId
    ];
    $stmt->execute($updateData);

    // 获取受影响的行数
    $affectedRows = $stmt->rowCount();
    if ($affectedRows > 0) {
        echo "修改成功!受影响行数:" . $affectedRows . "<br>";
    } else {
        echo "修改失败:未找到用户或数据未变更<br>";
    }} catch (PDOException $e) {
    echo "修改失败:" . $e->getMessage() . "<br>";} finally {
    PDODB::closeConnection();}

3.4 删除操作(Delete)

功能:根据用户 ID 删除指定用户数据。
php
运行
<?phprequire_once 'PDODB.php';try {
    $pdo = PDODB::getConnection();
    $userId = 1; // 要删除的用户ID

    // 定义删除 SQL
    $sql = "DELETE FROM users WHERE id = :id";
    $stmt = $pdo->prepare($sql);

    // 执行删除
    $stmt->execute([':id' => $userId]);

    $affectedRows = $stmt->rowCount();
    if ($affectedRows > 0) {
        echo "删除成功!已删除 ID 为 " . $userId . " 的用户<br>";
    } else {
        echo "删除失败:未找到该用户<br>";
    }} catch (PDOException $e) {
    echo "删除失败:" . $e->getMessage() . "<br>";} finally {
    PDODB::closeConnection();}

四、关键注意事项与安全优化

4.1 防 SQL 注入(重中之重)

SQL 注入是 Web 开发最常见的安全漏洞之一,攻击者通过构造恶意 SQL 语句窃取或篡改数据。PHP 中预防 SQL 注入的核心方案:
  1. 使用预处理语句:无论 PDO 还是 MySQLi,都必须使用 prepare() + execute() 绑定参数,严禁直接拼接 SQL 字符串(如下错误示范):

    php
    运行
    // 错误示范:直接拼接参数,存在 SQL 注入风险$sql = "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'";
  2. 过滤用户输入:对用户提交的参数(如表单、URL 参数)进行过滤,例如使用 trim() 去除空格、htmlspecialchars() 转义特殊字符。

4.2 常见问题排查

  1. 连接失败
    • 检查 MySQL 是否启动,端口号(3306)是否被占用。

    • 确认用户名、密码正确,且该用户有权限访问 php_db 数据库。

    • 若 MySQL 8.0+ 报 “认证方式错误”,需修改 MySQL 认证规则(参考:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';)。

  2. 中文乱码
    • 数据库、表、字段的编码必须统一为 utf8mb4(支持 emoji 表情)。

    • PHP 连接时需指定 charset=utf8mb4(PDO 已在 DSN 中配置)。

    • 网页输出时设置编码:header("Content-Type: text/html; charset=utf-8");

  3. 预处理语句执行失败
    • 检查占位符名称(如 :name)与绑定参数的键名是否一致。

    • 确认字段类型与参数类型匹配(如 age 是 int 类型,避免传入字符串)。

4.3 生产环境优化建议

  1. 配置文件分离:将数据库连接参数(host、username、password)放在独立的配置文件(如 config.php)中,且该文件放在网站根目录外(避免被直接访问):
    php
    运行
    // config.php(放在 htdocs 外)return [
        'host' => 'localhost',
        'dbname' => 'php_db',
        'username' => 'prod_user', // 生产环境使用低权限用户
        'password' => 'strong_password' // 复杂密码,避免明文];
    引入方式:$config = require '/path/to/config.php';
  2. 错误处理优化:生产环境禁用 die() 直接输出错误信息(避免泄露敏感信息),改为记录日志(如使用 error_log() 或日志框架):
    php
    运行
    catch (PDOException $e) {
        error_log("数据库错误:" . $e->getMessage(), 3, '/path/to/error.log'); // 写入日志
        echo "系统繁忙,请稍后再试!"; // 向用户显示友好提示}
  3. 使用数据库连接池:高并发场景下,频繁创建 / 关闭数据库连接会消耗大量资源,可使用连接池工具(如 php-pdo-pool)复用连接,提升性能。
  4. 限制数据库用户权限:生产环境中,PHP 连接数据库的用户仅授予 SELECTINSERTUPDATEDELETE 等必要权限,禁止授予 DROPALTER 等高危权限。

五、总结

本文详细讲解了 PHP 操作 MySQL 数据库的核心流程,重点掌握:
  1. 环境准备:确保 PHP 环境启用 PDO 扩展,创建测试数据库和表。

  2. 连接方式:推荐使用 PDO(通用性强、安全),封装工具类统一管理连接。

  3. CRUD 实现:基于 PDO 预处理语句实现新增、查询、修改、删除,避免 SQL 注入。

  4. 安全与优化:分离配置文件、记录错误日志、限制用户权限,适配生产环境。

PHP 操作数据库是动态网站开发的基础,掌握本文内容后,可应对大部分简单业务场景(如个人博客、小型管理系统)。建议大家多动手实践,尝试结合表单提交、用户登录等场景扩展功能,加深对 PDO 用法的理解。后续可进一步学习 ORM 框架(如 Eloquent、Doctrine),简化数据库操作代码。


分享给朋友:

“PHP 链接数据库与基础增删改查(CRUD)操作详解” 的相关文章

PHP 自定义鼠标样式完全指南:Web 场景实战(CSS 核心 + PHP 动态适配)

在 PHP 开发的 Web 应用中,自定义鼠标样式是提升界面个性化与用户体验的有效手段 —— 无论是电商平台的商品预览、创意官网的交互设计,还是后台管理系统的功能区分,合适的鼠标样式都能让操作逻辑更清晰、视觉效果更出彩。与 Java/Python 的桌面端 GUI 不同,PHP 作为服务器端语言,无...

PHP 实现在线视频播放完整方案:从后端存储到前端适配

在 Web 开发中,在线视频播放是电商展示、教育平台、企业宣传等场景的核心需求。PHP 作为主流的后端脚本语言,具备开发高效、部署简单、生态完善的优势,配合前端播放器组件,可快速实现跨浏览器、高兼容性的视频播放功能。本文将从技术选型、后端核心实现、前端集成、优化部署四个维度,手把手教你搭建 PHP...

Java 实现在线视频播放完整方案:从后端服务到前端播放

在 Web 开发中,在线视频播放是常见需求(如教育平台、视频网站、企业培训系统等)。Java 作为成熟的后端技术,能提供稳定的视频资源管理、权限控制、流式传输能力;配合前端播放器组件,可实现流畅的跨浏览器视频播放体验。本文将从技术选型、后端实现、前端集成、功能优化四个维度,手把手教你完成 Java...

Java 链接数据库与基础增删改查操作详解

在 Java 开发中,数据库交互是绝大多数应用的核心功能之一。无论是用户信息存储、业务数据统计还是日志记录,都需要通过 Java 程序与数据库建立连接并执行数据操作。本文将以 MySQL 数据库(最常用的关系型数据库之一)为例,从环境准备、数据库连接、基础增删改查(CRUD)操作到代码优化...

Unity 场景转换功能实现全指南:从基础到进阶

场景转换是几乎所有 Unity 项目都必备的核心功能,无论是简单的场景切换还是带有加载动画的复杂过渡,都直接影响着玩家的体验。本文将从基础原理出发,逐步讲解如何在 Unity 中实现各种场景转换效果,帮助开发者打造流畅自然的场景过渡体验。一、场景转换的基本原理在 Unity 中,场景转换本质上是卸载...