zoukankan      html  css  js  c++  java
  • 【PDO】PDO的使用【原创】

    具体参考《PHP核心技术与最佳实践》的5.1章 什么是PDO

    1. PDO的介绍

    PHP针对每种数据库都有一个独立的模块、一组独立的函数。这样的结构和设计让PHP兼容多种数据库变得困难。一旦要将一个应用移到另外一种数据库环境中,或者是需要添加新的数据库支持,就不得不重新编写和数据库相关的操作。通常编写多个类,用适配器模式来实现。在这个历史背景下PDO出现了。PDO(PHP Data Objects)提供了一个通用接口访问多种数据库,即抽象的数据模型支持连接多种数据库。有了PDO使代码变得更简洁、更安全。

    在PHP中,连接MySQL数据库的通常有3种方式:

    • MySQL系列函数:最常用,是过程式风格的一组应用(不建议,在PHP7.0已废除)
    • MySQLi系列函数:是MySQL函数的增强改进版,提供了过程化和面向对象两种风格的API,增加了预编译和参数绑定等新的特性
    • PDO:从语法上讲,PDO更接近MySQLi

    具体的可以参考:【连接数据库】PHP7的连接数据库的三种方法【原创】

    相比MySQLi,PDO的优势在于支持多种数据库,而MySQLi只能支持MySQL,所以一般更推荐使用PDO来对数据库进行操作。
    PDO提供了一个数据访问抽象层,这就意味着不管使用哪种数据库,都可以用同样一组API对数据进行操作,保证了可抽象性和访问接口的一致性。

    开启PDO很容易,一般来说安装好PHP默认都会开启PDO,如果没有则去php.ini中找到以下语句,把前面的分号去掉即可

    ;extension=php_pdo.dll

    2. PDO的使用

    使用PDO的第一步是配置数据源,之后的用法和MySQL扩展操作数据库的方法没有什么区别了,
    PDO的操作主要有PDO::query()、PDO::exec()、PDO::prepare()

    • PDO::query():主要是用于有记录结果返回的操作,特别是SELECT操作
    • PDO::exec():主要是针对没有结果集合返回的操作,比如INSERT、UPDATE、DELETE等操作,它返回的结果是当前操作影响的列数
    • PDO::prepare():主要是预处理操作,需要通过$rs->execute()来执行预处理里面的SQL语句,这个方法可以绑定参数,功能比较强大

    以下是PDO的示例:

    <?php
    /**
     * PDO 的使用实例
     */
    try {
        // 配置PDO的数据源
        $dsn = 'mysql: host=localhost; dbname=php_book';
    
        // 构造方法
        $db = new PDO($dsn, 'root', '123456');
    
        // 设置异常可捕获
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
        $db->exec("SET NAMES 'UTF8'");
    
        // 插入到日志中
        $sql = "INSERT INTO users(name, email, password, created_at) values ('pdo_test', '8888@qq.com', 'bbb', now())";
        $db->exec($sql);
    
        // 使用预处理语句
        $insert = $db->prepare("INSERT INTO users(name, email, password, created_at) values (?, ?, ?, now())");
        $insert->execute(array('pdo_test1', '8448657@qq.com', 'aaa'));
    
        // 异常
        $insert->execute(array('pdo_test2', '8448657@qq.com', 'aaa', 9, 10));
        $sql = "select name, email, password, created_at from users";
        $query = $db->prepare($sql);
        $query->execute();
    
        var_dump($query->fetchAll(PDO::FETCH_ASSOC));
    } catch (PDOException $e) {
        echo $e->getMessage();
    }

    注意:使用PDO从MySQL数据库查询出来的数据都是string类型的,在某些特殊应用下,可能需要转换格式

    3. PDO的参数绑定和预编译

    PDO最大的特点就是引入参数绑定和预编译。

    下面是从数据库中查询某条记录:

    <?php
    $pdo = new PDO('mysql: host=localhost; dbname=php_book');
    $pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']);

    这是一段糟糕的代码。插入一个原始的请求参数到 SQL 请求中。这将让被黑客轻松地利用[SQL 注入]方式进行攻击。想一下如果黑客将一个构造的 id 参数通过像 http://domain.com/?id=1%3BDELETE+FROM+users 这样的 URL 传入。这将会使 $_GET[‘id’] 变量的值被设为 1;DELETE FROM users 然后被执行从而删除所有的 user 记录!因此,你应该使用 PDO 限制参数来过滤 ID 输入。

    上面的代码可优化为:

    <?php
    $pdo = new PDO('mysql: host=localhost;dbname=php_book');
    $stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
    $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    $stmt->execute();

    在MySQL应用中,为了防止注入攻击,通常在PHP中使用intval、addslashes等函数对传入的参数进行转义,转变为SQL中合法的参数类型,这种方法较复杂,而使用PDO的bindParam方法会变得很快捷,只需要在函数中指定第三个参数,即可对传入的参数进行转换,转换为需要的类型拼接到原生的SQL语句中

    比如:

    <?php
    /**
     * PDO 的最大特点是引入参数绑定和预编译
     * 参数绑定:通过绑定变量来执行准备好的语句
     * 两种绑定参数的方式
     */
    $calories = 150;
    $colour = 'red';
    
    // 配置PDO的数据源
    $dsn = 'mysql: host=localhost; dbname=php_book';
    
    // 构造方法
    $db = new PDO($dsn, 'root', '123456');
    
    // 执行预处理语句(第一种绑定变量的方式)
    $sth = $db->prepare('SELECT name, colour, calories FROM fruit WHERE calories > :calories AND colour = :colour');
    
    // 绑定变量,将变量转化为int类型
    $sth->bindParam(':calories', $calories, PDO::PARAM_INT);
    
    // 绑定变量,将变量转化为string类型
    $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
    
    // 执行
    $sth->execute();
    var_dump($sth->fetchAll(PDO::FETCH_ASSOC));
    
    // 执行预处理语句(第二种绑定变量的方式)
    $sth = $db->prepare('SELECT name, colour, calories FROM fruit WHERE calories > ? AND colour = ?');
    
    // 绑定变量,将变量转化为int类型
    $sth->bindParam(1, $calories, PDO::PARAM_INT);
    
    // 绑定变量,将变量转化为string类型
    $sth->bindParam(2, $colour, PDO::PARAM_STR, 12);
    
    // 执行
    $sth->execute();
    var_dump($sth->fetchAll(PDO::FETCH_ASSOC));

    预编译负责两件事,转义和软解析提速。程序要支持预编译,除了要数据库支持外,还需要驱动支持(PDO和MySQLi均支持)

    4. PDO事务处理

    一个事务中所有的工作在提交时,即使是分阶段执行,也要保证安全的应用于数据库,不被其他的连接干扰,事务工作可以在请求发生错误时自动取消。
    事务的主要特性:原子性、一致性、独立性、持久性(Atomicity,Consistency,Isolation,Durability,ACID)。典型运用就是通过把批量的改变保存,然后立即执行,这样就能提高效率,一旦事务不成功,将会回滚到初始状态,保证数据的一致性。

    SQL通常工作在自动提交模式下,这意味着执行的每个查询都有自己隐含的事务处理,无论是数据库支持事务还是因数据库不支持而不存在事务,DML语句执行的结果都将立即生效而不可更改。比如在MySQL中执行一条update语句,其功能将会立即生效并且是永久性不可更改性的。而在Oracle数据库中,默认是事务模式,要delete一条数据,数据并不会被永久性删除,只有执行了commit命令后才会生效。

    PDO中使用beginTransaction()方法来创建事务。在一个事务中,使用commit()或者是rollback()方法来结束事务,具体应用哪种方法这取决于事务中代码运行是否成功。脚本结束或者一个连接要关闭时,如果还有一个未处理完的事务,PDO自动将其回滚。这对于脚本意外终止情况来说是一个安全方案,如果没有明确提交事务,它将假设发生一些错误,为数据的安全执行回滚。

    自动回滚仅发生于通过beginTransaction()建立的事务。如果用手动方式执行一个开始事务的查询,PDO无法知道他的情况故无法回滚。

    代码如下:

    <?php
    
    try {
        $conn = new PDO('mysql: host=localhost; dbname=php_book', 'root', '123456');
    
        // 开启事务
        $conn->beginTransaction();
    
        for($i = 0; $i < 1000000; $i++) {
            $conn->exec("insert into `users` values(null, 'username')");
        }
    
        // 提交事务
        $conn->commit();
    } catch(PDOException $ex) {
        // 执行回滚
        $conn->rollBack();
    } 

    注意:因为使用了事务,要么成功要么失败,如果发现第一条执行了,但是第二条没有执行或者是失败了,则应该检查一下表类型是否为MyISAM,MyISAM引擎是不支持事务的,需要改用InnoDB或者其他的支持事务的引擎。

  • 相关阅读:
    PyTorch-->Tensors(张量)
    Pytorch-->PyTorch学习(1)
    信息安全四大顶会!!!
    2020春季数据库-->关系演算安全性的理解
    2020春季数据库-->三级模式和两层映像
    2020寒假->Web编程(1)
    Httprequseter 插件使用
    YII2 客户端验证
    谷歌网页全屏截图
    后台新订单提醒
  • 原文地址:https://www.cnblogs.com/linewman/p/9918100.html
Copyright © 2011-2022 走看看