热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

通过PDO扩展与MySQL数据库交互实现增删改查实现和数据库事务

本文介绍通过PDO扩展与MySQL数据库交互实现增删改查实现和数据库事务。

相关学习推荐:mysql教程

通过预处理语句进行增删改查

为什么使用预处理语句

关于预处理语句我们在上篇教程中已经简单介绍过,我们可以将其与视图模板类比,所谓预处理语句就是预定义的 SQL 语句模板,其中的具体参数值通过占位符替代:

INSERT INTO REGISTRY (name, value) VALUES (?, ?)
INSERT INTO REGISTRY (name, value) VALUES (:name, :value)

然后在后续真正要执行 SQL 语句之前,再通过特定 API 方法将具体参数值与对应占位符进行绑定和映射。就好比定义的视图模板也是将变量通过特定占位符替代,然后真正渲染时将变量值传递进来填充和渲染一样。

为什么要费这番周折呢?直接用前面演示的 query 方法进行增删改查操作它不香吗?呃,那我们接下来来说说预处理语句的好处,或者说为什么要使用预处理语句进行数据库交互,好处有二:

  • 首先,使用预处理语句提前定义的 SQL 模板只会解析一次,但可以通过传递不同的参数值执行多次,从而避免模板相同的 SQL 语句重复分析、编译和优化,提高数据库操作执行速度;
  • 其次,后期传递给预处理语句的参数值会被底层驱动进行处理,从而有效避免 SQL 注入攻击。

综上,从性能和安全角度考虑,推荐使用预处理语句处理数据库的增删改查操作。

增删改查示例代码

接下来,我们基于 PDO 提供的预处理语句 API 实现 MySQL 数据库的增删改查操作,我们将通过面向对象的方式来实现:

pdo = $pdo;
        }
    }

    public function insert($title, $content)
    {
        $sql = 'INSERT INTO `post` (title, content, created_at) VALUES (:title, :content, :created_at)';
        try {
            // 准备预处理语句
            $stmt = $this->pdo->prepare($sql);
            // 获取当前时间对应的格式化字符串:2020-05-28 13:00:00
            $datetime = date('Y-m-d H:i:s', time());
            // 绑定参数值
            $stmt->bindParam(':title', $title, PDO::PARAM_STR);
            $stmt->bindParam(':content', $content, PDO::PARAM_STR);
            $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR);
            // 执行语句
            $stmt->execute();
            return $this->pdo->lastInsertId();  // 返回插入记录对应ID
        } catch (PDOException $e) {
            printf("数据库插入失败: %s\n", $e->getMessage());
        }
    }

    public function select($id)
    {
        $sql = 'SELECT * FROM `post` WHERE id = ?';
        try {
            // 准备预处理语句
            $stmt = $this->pdo->prepare($sql);
            // 绑定参数值
            $stmt->bindValue(1, $id, PDO::PARAM_INT);
            // 执行语句
            $stmt->execute();
            return $stmt->fetchObject(self::class);  // 以对象方式返回结果集
        } catch (PDOException $e) {
            printf("数据库查询失败: %s\n", $e->getMessage());
        }
    }

    public function selectAll()
    {
        $sql = 'SELECT * FROM `post` ORDER BY id DESC';
        try {
            // 准备预处理语句
            $stmt = $this->pdo->prepare($sql);
            // 执行语句
            $stmt->execute();
            return $stmt->fetchAll();  // 返回所有结果集
        } catch (PDOException $e) {
            printf("数据库查询失败: %s\n", $e->getMessage());
        }
    }

    public function update($id)
    {
        $sql = 'UPDATE `post` SET created_at = :created_at WHERE id = :id';
        try {
            // 准备预处理语句
            $stmt = $this->pdo->prepare($sql);
            $datetime = date('Y-m-d H:i:s', time());
            // 绑定参数值
            $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR);
            $stmt->bindValue(':id', $id, PDO::PARAM_INT);
            // 执行语句
            $stmt->execute();
            return $stmt->rowCount();
        } catch (PDOException $e) {
            printf("数据库更新失败: %s\n", $e->getMessage());
        }
    }

    public function delete($id)
    {
        $sql = 'DELETE FROM `post` WHERE id = ?';
        try {
            // 准备预处理语句
            $stmt = $this->pdo->prepare($sql);
            // 绑定参数值
            $stmt->bindValue(1, $id, PDO::PARAM_INT);
            // 执行语句
            $stmt->execute();
            return $stmt->rowCount();
        } catch (PDOException $e) {
            printf("数据库删除失败: %s\n", $e->getMessage());
        }
    }
}

我们构建了一个 Post 类,然后在构造函数中初始化 $pdo 实例(从外部传入),然后将基于预处理语句实现的增删改查操作分解到对应的类方法中。整体逻辑非常简单,以 insert 为例,首先通过 PDO 对象的 prepare 方法传入 SQL 模板构建预处理语句,该方法返回 PDOStatement 对象,接下来,就是调用该对像的 bindParam 方法绑定具体参数值,该方法的第一个参数是占位符,第二个参数是参数值,第三个参数是值类型(对应的常量可以在 PDO 预定义常量中查询),绑定好参数后,就可以调用 PDOStatement 对象的 execute 方法执行预处理语句了。

对于插入操作,可以通过 PDO 对象上的 lastInsertId 方法返回插入记录的主键 ID,对于更新和删除方法,可以通过 PDOStatement 对象上的 rowCount 方法返回受影响行数表示是否操作成功。对于查询操作,可以通过 PDOStatement 对象的 fetch 方法返回单条记录,也可以通过 fetchObject 方法返回映射到指定类后的对象实例(也是单条记录),对于多个结果,可以通过 fetchAll 方法返回。

需要注意的是,在声明预处理语句的时候,可以通过 ? 占位符,也可以通过 :name 这种可读性更好的占位符,然后在绑定参数时,既可以通过 bindValue 也可以通过 bindParam 方法,两者传递参数一样,只是对于 ? 占位符,需要通过数值序号建立与 SQL 模板的映射(从 1 开始)。

结合代码和 PHP 官方文档理解上面的代码并不困难,接下来,我们来编写测试代码:

// 初始化 PDO 连接实例
$dsn = 'mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8mb4';
$user = 'root';
$pass = 'root';
try {
    $pdo = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
    printf("数据库连接失败: %s\n", $e->getMessage());
}

// 测试代码
$post = new Post($pdo);
// insert
$title = '这是一篇测试文章';
$cOntent= '测试内容: 今天天气不错';
$id = $post->insert($title, $content);
echo '文章插入成功: ' . $id . '
'; // select $item = $post->select($id); echo '
';
print_r($item);
// update
$affected = $post->update($id);
echo '受影响的行数: ' . $affected . '
'; // delete $affected = $post->delete($id); echo '受影响的行数: ' . $affected . '
'; // selectAll $items = $post->selectAll(); print_r($items);

初始化一个 PDO 对象实例传入 Post 构造函数,然后依次调用 Post 对象的增删改查方法。在浏览器中访问,打印结果如下:

更多模式设置,请参考官方文档中 fetchAll 方法的介绍和示例。

数据库事务

最后,我们再来看看如何通过 PDO 扩展实现数据库事务的提交和回滚,我们已经知道,对于单条 SQL 语句而言,事务提交和回滚是自动完成的,对于 SQL 语句序列(多条 SQL 语句),则需要显式开启事务和提交事务,PDO 对象也为此提供了对应的 API 方法。非常简单,比如我们在 Post 类中新增一个批量插入方法 batchInsert 方法:

public function batchInsert(array $items)
{
    $sql = 'INSERT INTO `post` (title, content, created_at) VALUES (:title, :content, :created_at)';
    try {
        // 开启事务
        $this->pdo->beginTransaction();
        // 准备预处理语句
        $stmt = $this->pdo->prepare($sql);
        foreach ($items as $item) {
            // 绑定参数值
            $datetime = date('Y-m-d H:i:s', time());
            $stmt->bindParam(':title', $item->title, PDO::PARAM_STR);
            $stmt->bindParam(':content', $item->content, PDO::PARAM_STR);
            $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR);
            // 执行语句
            $stmt->execute();
        }
        $this->pdo->commit(); // 提交事务
        return $stmt->rowCount();  // 返回受影响的行数
    } catch (PDOException $e) {
        $this->pdo->rollBack(); // 回滚事务
        printf("数据库批量插入失败: %s\n", $e->getMessage());
    }
}

我们只需要在执行 SQL 序列之前调用 PDO 对象的 beginTransaction 方法开启事务,然后在所有 SQL 语句执行完成后调用 commit 方法提交事务,如果 SQL 执行过程中出错,则在异常处理代码中通过 PDO 对象的 rollBack 方法回滚事务。

为上述方法编写测试代码:

$post = new Post($pdo);
$items = [
    [
        'title' => '这是一篇测试文章111',
        'content' => '测试内容'
    ],
    [
        'title' => '这是一篇测试文章222',
        'content' => '测试内容'
    ],
    [
        'title' => '这是一篇测试文章333',
        'content' => '测试内容'
    ],
];
$post->batchInsert($items);
$items = $post->selectAll();
print_r($items);

执行这段代码,打印结果中包含新插入的文章数据,则表明事务提交成功:

以上就是通过PDO扩展与MySQL数据库交互 实现增删改查实现和数据库事务的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • 软件测试行业深度解析:迈向高薪的必经之路
    本文深入探讨了软件测试行业的发展现状及未来趋势,旨在帮助有志于在该领域取得高薪的技术人员明确职业方向和发展路径。 ... [详细]
  • 在使用mybatis进行mapper.xml测试的时候发生必须为元素类型“mapper”声明属性“namespace”的错误项目目录结构UserMapper和UserMappe ... [详细]
  • Windows环境下Oracle数据库迁移实践
    本文详细记录了一次在Windows操作系统下将Oracle数据库的控制文件、数据文件及在线日志文件迁移至外部存储的过程,旨在为后续的集群环境部署做好准备。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 美团安全响应中心推出全新配送业务测试活动,带来双重福利,邀您共同参与! ... [详细]
  • 解决ADODB连接Access时出现80004005错误的方法
    本文详细介绍了如何解决在使用ADODB连接Access数据库时遇到的80004005错误,包括错误原因分析和具体的解决步骤。 ... [详细]
  • 本文详细解析了MySQL中常见的几种错误,并提供了具体的解决方法,帮助开发者快速定位和解决问题。 ... [详细]
  • 搭建个人博客:WordPress安装详解
    计划建立个人博客来分享生活与工作的见解和经验,选择WordPress是因为它专为博客设计,功能强大且易于使用。 ... [详细]
  • 七大策略降低云上MySQL成本
    在全球经济放缓和通胀压力下,降低云环境中MySQL数据库的运行成本成为企业关注的重点。本文提供了一系列实用技巧,旨在帮助企业有效控制成本,同时保持高效运作。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 本文介绍了如何通过安装 sqlacodegen 和 pymysql 来根据现有的 MySQL 数据库自动生成 ORM 的模型文件(model.py)。此方法适用于需要快速搭建项目模型层的情况。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 探讨密码安全的重要性
    近期,多家知名网站如CSDN、人人网、多玩、开心网等的数据库相继被泄露,其中大量用户的账户密码因明文存储而暴露无遗。本文将探讨黑客获取密码的常见手段,网站如何安全存储用户信息,以及用户应如何保护自己的密码。 ... [详细]
  • 本文介绍如何通过参数化查询来防止SQL注入攻击,确保数据库的安全性。示例代码展示了在C#中使用参数化查询添加学生信息的方法。 ... [详细]
author-avatar
手机用户2502916257
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有