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

在 PHP 开发中,数据库交互是 Web 应用的核心能力 —— 无论是用户登录注册、商品数据管理,还是内容发布存储,都需要通过 PHP 与数据库建立连接并执行操作。本文以 MySQL 数据库 为例,从环境准备、数据库连接、基础 CRUD(创建 / 读取 / 更新 / 删除)操作三个维度,手把手教你实现 PHP 与数据库的交互,适合 PHP 初学者快速入门。

一、环境准备:搭建基础开发环境

在编写代码前,需确保本地已配置好以下工具和环境,避免后续出现兼容性或依赖问题。

1.1 核心工具清单

PHP 运行环境

解析执行 PHP 代码(如 WAMP、XAMPP、MAMP)

7.4 及以上(LTS)

MySQL 数据库

提供数据存储服务的关系型数据库

5.7 或 8.0

代码编辑器

编写 PHP 代码(如 VS Code、PhpStorm)

任意支持 PHP 的编辑器

浏览器 / Postman

测试 Web 接口或 PHP 脚本执行结果

最新版本

1.2 环境验证

  1. 启动 PHP 运行环境(如 XAMPP 启动 Apache 和 MySQL)。
  2. 新建 phpinfo.php 文件,写入以下代码并放在 Web 根目录(如 XAMPP 的 htdocs 文件夹):php运行
  3. 浏览器访问 http://localhost/phpinfo.php,若能看到 PHP 配置页面,且搜索到 mysqli 或 PDO 扩展(默认已启用),说明环境正常。

1.3 提前创建数据库和表

为测试 CRUD 操作,先在 MySQL 中创建示例数据库和表(以「用户表 user」为例):

  1. 打开 MySQL 管理工具(如 XAMPP 的 phpMyAdmin,访问 http://localhost/phpmyadmin)。
  2. 执行以下 SQL 创建数据库和表:sql

  • 表说明:utf8mb4 编码支持表情符号,create_time 自动记录数据插入时间,符合实际开发场景。

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

PHP 连接 MySQL 主要有两种方式:MySQLi(MySQL Improved,仅支持 MySQL)和 PDO(PHP Data Objects,支持多数据库)。本文重点讲解 PDO(推荐,兼容性强、支持预处理防 SQL 注入),同时补充 MySQLi 示例。

2.1 封装数据库连接工具类(PDO 方式)

为避免重复编写连接逻辑,封装 DB.php 工具类,统一管理连接配置和资源释放:

php

运行

<?php
/**
 * 数据库连接工具类(PDO 方式)
 */
class DB {
    // 数据库配置(根据你的本地环境修改)
    private static $host = 'localhost'; // 数据库主机(默认 localhost)
    private static $dbname = 'php_db'; // 数据库名
    private static $username = 'root'; // MySQL 用户名(默认 root)
    private static $password = ''; // MySQL 密码(XAMPP 默认空,WAMP 可能为 root)
    private static $charset = 'utf8mb4'; // 数据库编码
    private static $pdo = null; // 存储 PDO 连接实例(单例模式)

    /**
     * 获取数据库连接(单例模式,避免重复创建连接)
     * @return PDO|null 连接实例
     */
    public static function getConnection() {
        // 若已存在连接,直接返回
        if (self::$pdo !== null) {
            return self::$pdo;
        }

        try {
            // PDO 连接字符串格式:mysql:host=主机;dbname=数据库名;charset=编码
            $dsn = "mysql:host=" . self::$host . ";dbname=" . self::$dbname . ";charset=" . self::$charset;
            
            // 创建 PDO 实例(第三个参数:数组配置,设置错误模式为异常)
            self::$pdo = new PDO($dsn, self::$username, self::$password, [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 开启异常报错(便于调试)
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // 默认查询结果为关联数组
            ]);
            echo "数据库连接成功!<br>";
            return self::$pdo;
        } catch (PDOException $e) {
            // 捕获连接异常,输出错误信息并终止脚本
            die("数据库连接失败:" . $e->getMessage() . "<br>");
        }
    }

    /**
     * 关闭数据库连接(PDO 会自动关闭,手动关闭可选)
     */
    public static function closeConnection() {
        self::$pdo = null;
        echo "数据库连接已关闭!<br>";
    }
}

// 测试连接(可选)
// DB::getConnection();
// DB::closeConnection();
?>

2.2 MySQLi 连接示例(备用)

若需使用 MySQLi(面向对象方式),连接代码如下(不推荐,仅作参考):

php

运行

<?php
// MySQLi 连接配置
$host = 'localhost';
$dbname = 'php_db';
$username = 'root';
$password = '';

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

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

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

三、基础 CRUD 操作实现(PDO 方式)

以下所有操作均基于 DB.php 工具类,通过 PDO 预处理语句执行 SQL(防 SQL 注入),并封装成可复用的函数。

3.1 新增操作(Create):插入用户数据

需求:向 user 表插入一条用户数据(username=「李四」,age=28,email=「lisi@xxx.com」)。

实现代码(create_user.php)

php

运行

<?php
// 引入数据库连接类
require_once 'DB.php';

/**
 * 新增用户
 * @param string $username 用户名
 * @param int $age 年龄
 * @param string $email 邮箱
 * @return bool|int 成功返回用户ID,失败返回false
 */
function createUser($username, $age, $email) {
    try {
        $pdo = DB::getConnection();
        
        // SQL 插入语句(:username 是命名占位符,更易读)
        $sql = "INSERT INTO user (username, age, email) VALUES (:username, :age, :email)";
        
        // 准备预处理语句
        $stmt = $pdo->prepare($sql);
        
        // 绑定参数(或直接在 execute 中传入关联数组)
        $params = [
            ':username' => $username,
            ':age' => $age,
            ':email' => $email
        ];
        
        // 执行 SQL(返回 bool 值)
        $result = $stmt->execute($params);
        
        if ($result) {
            // 返回新增用户的自增 ID
            return $pdo->lastInsertId();
        }
        return false;
    } catch (PDOException $e) {
        echo "新增用户失败:" . $e->getMessage() . "<br>";
        return false;
    }
}

// 测试新增操作
$userId = createUser("李四", 28, "lisi@xxx.com");
if ($userId) {
    echo "新增用户成功!用户ID:" . $userId . "<br>";
} else {
    echo "新增用户失败!<br>";
}

// 关闭连接(可选)
DB::closeConnection();
?>

验证结果:访问 http://localhost/create_user.php,若输出「新增用户成功!用户 ID:1」,则在 phpMyAdmin 中查看 user 表,可看到新增的记录。

3.2 查询操作(Read):查询用户数据

需求:两种常见查询场景:

  1. 单条查询:根据 id 查询指定用户。
  2. 批量查询:查询所有用户或符合条件的用户。

3.2.1 单条查询(按 ID 查询)

php

运行

<?php
require_once 'DB.php';

/**
 * 根据 ID 查询用户
 * @param int $id 用户ID
 * @return array|false 成功返回用户数组,失败返回false
 */
function getUserById($id) {
    try {
        $pdo = DB::getConnection();
        
        $sql = "SELECT id, username, age, email, create_time FROM user WHERE id = :id";
        $stmt = $pdo->prepare($sql);
        
        // 绑定参数(int 类型,可选指定参数类型)
        $stmt->bindParam(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        
        // 获取单条结果(关联数组)
        $user = $stmt->fetch();
        
        return $user ? $user : false;
    } catch (PDOException $e) {
        echo "查询用户失败:" . $e->getMessage() . "<br>";
        return false;
    }
}

// 测试查询(查询 ID=1 的用户)
$user = getUserById(1);
if ($user) {
    echo "查询到的用户:<br>";
    echo "ID:" . $user['id'] . "<br>";
    echo "用户名:" . $user['username'] . "<br>";
    echo "年龄:" . $user['age'] . "<br>";
    echo "邮箱:" . $user['email'] . "<br>";
    echo "创建时间:" . $user['create_time'] . "<br>";
} else {
    echo "未查询到该用户!<br>";
}

DB::closeConnection();
?>

3.2.2 批量查询(查询所有用户)

php

运行

<?php
require_once 'DB.php';

/**
 * 查询所有用户
 * @return array 用户列表数组(空数组表示无数据)
 */
function getAllUsers() {
    try {
        $pdo = DB::getConnection();
        
        $sql = "SELECT id, username, age, email, create_time FROM user ORDER BY id DESC";
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        
        // 获取所有结果(关联数组)
        $users = $stmt->fetchAll();
        
        return $users;
    } catch (PDOException $e) {
        echo "查询所有用户失败:" . $e->getMessage() . "<br>";
        return [];
    }
}

// 测试批量查询
$userList = getAllUsers();
if (!empty($userList)) {
    echo "查询到 " . count($userList) . " 个用户:<br>";
    foreach ($userList as $user) {
        echo "ID:" . $user['id'] . ",用户名:" . $user['username'] . ",邮箱:" . $user['email'] . "<br>";
    }
} else {
    echo "暂无用户数据!<br>";
}

DB::closeConnection();
?>

3.3 更新操作(Update):修改用户数据

需求:将 id=1 的用户年龄修改为 30,邮箱修改为「lisi_update@xxx.com」。

实现代码(update_user.php)

php

运行

<?php
require_once 'DB.php';

/**
 * 更新用户信息
 * @param int $id 用户ID
 * @param array $data 要更新的字段(如 ['age' => 30, 'email' => 'xxx'])
 * @return bool 成功返回true,失败返回false
 */
function updateUser($id, $data) {
    try {
        $pdo = DB::getConnection();
        
        // 拼接更新字段(动态生成 SET 部分,避免字段固定)
        $updateFields = [];
        foreach ($data as $key => $value) {
            $updateFields[] = "$key = :$key";
        }
        $sql = "UPDATE user SET " . implode(', ', $updateFields) . " WHERE id = :id";
        
        $stmt = $pdo->prepare($sql);
        
        // 合并参数(更新字段 + ID)
        $params = array_merge($data, ['id' => $id]);
        $result = $stmt->execute($params);
        
        // 返回受影响的行数(>0 表示更新成功)
        return $stmt->rowCount() > 0;
    } catch (PDOException $e) {
        echo "更新用户失败:" . $e->getMessage() . "<br>";
        return false;
    }
}

// 测试更新操作(修改 age 和 email)
$updateData = [
    'age' => 30,
    'email' => **********'
];
$isSuccess = updateUser(1, $updateData);
if ($isSuccess) {
    echo "更新用户成功!<br>";
} else {
    echo "更新用户失败(可能 ID 不存在或数据未变更)!<br>";
}

DB::closeConnection();
?>

3.4 删除操作(Delete):删除用户数据

需求:删除 id=1 的用户数据。

实现代码(delete_user.php)

php

运行

<?php
require_once 'DB.php';

/**
 * 根据 ID 删除用户
 * @param int $id 用户ID
 * @return bool 成功返回true,失败返回false
 */
function deleteUser($id) {
    try {
        $pdo = DB::getConnection();
        
        $sql = "DELETE FROM user WHERE id = :id";
        $stmt = $pdo->prepare($sql);
        $stmt->bindParam(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        
        // 返回受影响的行数(>0 表示删除成功)
        return $stmt->rowCount() > 0;
    } catch (PDOException $e) {
        echo "删除用户失败:" . $e->getMessage() . "<br>";
        return false;
    }
}

// 测试删除操作
$isSuccess = deleteUser(1);
if ($isSuccess) {
    echo "删除用户成功!<br>";
} else {
    echo "删除用户失败(可能 ID 不存在)!<br>";
}

DB::closeConnection();
?>

四、常见问题与注意事项

  1. 连接失败排查:确认 MySQL 已启动(XAMPP 中检查 MySQL 服务状态)。检查 DB.php 中的 username 和 password 是否与本地 MySQL 配置一致(XAMPP 默认为 root/ 空,WAMP 可能为 root/root)。若报错「Unknown database 'php_db'」,需先手动创建数据库或执行创建数据库的 SQL。
  2. SQL 注入防护:严禁直接拼接用户输入到 SQL 中(如 $sql = "SELECT * FROM user WHERE username = '$username'"),恶意用户可通过输入 ' OR 1=1 # 绕过验证。必须使用 PDO 预处理语句(prepare + execute),通过占位符(:name 或 ?)绑定参数,PDO 会自动转义特殊字符,彻底防 SQL 注入。
  3. 编码问题(中文乱码):数据库创建时指定 utf8mb4 编码(支持中文和表情)。PDO 连接字符串中添加 charset=utf8mb4(已在 DB.php 中配置)。网页输出时设置编码:header("Content-Type: text/html; charset=utf-8");。
  4. 错误调试技巧:PDO 开启 ERRMODE_EXCEPTION 后,可通过 try-catch 捕获异常,输出 $e->getMessage() 查看具体错误(如 SQL 语法错误、字段名错误)。测试脚本时,先单独执行 SQL(如在 phpMyAdmin 中),确认 SQL 正确后再写入 PHP 代码。
  5. 资源释放:PDO 连接会在脚本执行结束后自动关闭,手动调用 closeConnection() 仅作规范,非必需。预处理语句($stmt)执行后无需手动关闭,脚本结束后自动释放。

五、进阶方向

本文讲解的是 PHP 原生 PDO 操作,实际开发中可通过框架简化代码:

  • Laravel:PHP 主流框架,内置 Eloquent ORM,无需编写 SQL 即可实现 CRUD(如 User::create($data)User::find($id))。
  • ThinkPHP:国内常用框架,提供 Db 类封装,支持链式操作(如 Db::table('user')->where('id', 1)->update($data))。
  • Medoo:轻量级数据库框架(仅 1 个文件),适合小型项目,简化 PDO 冗余代码。

若你已掌握本文的基础操作,可进一步学习这些框架,提升开发效率;同时建议了解「事务处理」「分页查询」「联表查询」等进阶功能,应对复杂业务场景。

至此,PHP 链接数据库与基础 CRUD 操作已全部讲解完毕。建议动手实践每一步,遇到报错时对照「常见问题」排查,逐步理解 PHP 与数据库交互的核心逻辑。

s6fr9.hsd-stone.com

xm3t6.hsd-stone.com

1aa5k.hsd-stone.com

ww7j7.hsd-stone.com

31szl.hsd-stone.com

bwajx.hsd-stone.com

ewk3n.hsd-stone.com

i26zn.hsd-stone.com

j607t.hsd-stone.com

p62s7.hsd-stone.com

m7ip4.hsd-stone.com

1s2tn.hsd-stone.com

fd5ig.hsd-stone.com

tx9z0.hsd-stone.com

ryow1.hsd-stone.com

hrhyt.hsd-stone.com

da3pr.hsd-stone.com

nxjih.hsd-stone.com

4g4lu.hsd-stone.com

53t9l.hsd-stone.com

全部评论

相关推荐

牛客41406533...:回答他在课上学,一辈子待在学校的老教授用三十年前的祖传PPT一字一句的讲解,使用谭浩强红皮书作为教材在devc++里面敲出a+++++a的瞬间爆出114514个编译错误来学这样才显得专业
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务