资讯专栏INFORMATION COLUMN

PDO的使用

Magicer / 3044人阅读

具体参考《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的示例:

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最大的特点就是引入参数绑定和预编译。

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

query("SELECT name FROM users WHERE id = " . $_GET["id"]);

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

上面的代码可优化为:

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语句中

比如:

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无法知道他的情况故无法回滚。

代码如下:

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或者其他的支持事务的引擎。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/17664.html

相关文章

  • (唯一合适) PDO 教程

    摘要:是什么首先思考为什么选择是一个数据访问抽象层抽象是双重的一个是众所周知但不太重要的另一个是模糊的但是是最重要的众所周知为不同的数据库提供了统一的接口虽然这个功能本身很庞大但是对于固定程序来说不是过于重要的事情基本所有的程序都是使用统一的后端 PDO是什么 首先思考, 为什么选择PDO PDO 是一个数据访问抽象层(Database Access Abstraction Layer). ...

    sf190404 评论0 收藏0
  • PDO使用

    具体参考《PHP核心技术与最佳实践》的5.1章 《什么是PDO》 1. PDO的介绍 PHP针对每种数据库都有一个独立的模块、一组独立的函数。这样的结构和设计让PHP兼容多种数据库变得困难。一旦要将一个应用移到另外一种数据库环境中,或者是需要添加新的数据库支持,就不得不重新编写和数据库相关的操作。通常编写多个类,用适配器模式来实现。在这个历史背景下PDO出现了。PDO(PHP Data Objec...

    call_me_R 评论0 收藏0
  • PHP 数据库操作

    摘要:操作数据库的种形式使用扩展类库推荐使用扩展类库这是类库的升级版,但已经不推荐使用扩展包含哪三个类与区别可以支持多种数据库,而且操作方法一致只支持数据库如何使用连接数据库什么是如何关闭连接通过来连接数据库,其中必须传入数据源名称数据源名称是 PHP操作数据库的2种形式 使用 PDO 扩展类库(推荐) 使用 Mysqli 扩展类库(这是Mysql类库的升级版,但已经不推荐使用) PDO...

    Jingbin_ 评论0 收藏0

发表评论

0条评论

Magicer

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<