目录

mysql扩展

从 PHP 5.5.0 起这个扩展已经被废弃,并且从 PHP 7.0.0. 开始被移除。作为替代,可以使用 mysqli 或者 PDO_MySQL 扩展代替。

mysqli扩展

mysqli扩展,我们有时称之为MySQL增强扩展,可以用于使用 MySQL4.1.3或更新版本中新的高级特性。mysqli扩展在PHP 5及以后版本中包含。

相对于mysql扩展的提升主要有:

  • 面向对象接口
  • prepared语句支持(译注:关于prepare请参阅mysql相关文档)
  • 多语句执行支持
  • 事务支持
  • 增强的调试能力
  • 嵌入式服务支持

关于mysqli的持久化实现:

从 PHP 5.3 mysqli 扩展开始支持持久化连接。持久化连接已经在 PDO MYSQL 和 ext/mysql 中提供支持。持久化连接的目的在于重用客户端到服务器之间的连接,而不是每次在需要的时候都重新建立一个连接。由于持久化连接可以将已经建立的连接缓存起来,以备后续的使用,所以省去了建立新的连接的开销,因此可以带来性能上的提升。

不像 mysql 扩展,mysqli 没有提供一个特殊的方法用于打开持久化连接。需要打开一个持久化连接时,你必须在连接时在主机名前增加 p:

使用持久化连接也会存在一些风险,因为在缓存中的连接可能处于一种不可预测的状态。例如,如果客户端未能正常关闭连接,可能在这个连接上残留了对库表的锁,那么当这个连接被其他请求重用的时候,这个连接还是处于 “有锁的状态”。所以,如果要很好的使用持久化连接,那么要求代码在和数据库进行交互的时候,确保做好清理工作,保证被缓存的连接是一个干净的,没有残留的状态。

mysqli 扩展的持久化连接提供了内建的清理处理代码。 mysqli 所做的清理工作包括:

  • 回滚处于活动状态的事务
  • 关闭并且删除临时表
  • 对表解锁
  • 重置会话变量
  • 关闭预编译 SQL 语句(在PHP中经常发生)
  • 关闭处理程序
  • 释放通过 GET_LOCK() 获得的锁

这确保了将连接返回到连接池的时候,它处于一种"干净"的状态,可以被其他客户端进程所使用。

mysqli 扩展通过自动调用 C-API 函数 mysql_change_user() 来完成这个清理工作。

自动清理的特性有优点也有缺点。优点是程序员不再需要担心附加的清理代码,因为它们会自动调用。然而缺点就是性能可能会慢一点,因为每次从连接池返回一个连接都需要执行这些清理代码。

这个自动清理的代码可以通过在编译 php 时定义 MYSQLI_NO_CHANGE_USER_ON_PCONNECT 来关闭。

PDO

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 PDO 驱动 来访问数据库服务。

PDO 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。 PDO 不提供 数据库 抽象层;它不会重写 SQL,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。

当然,PDO也有它自己的先进性,比如一个干净的,简单的,可移植的API,它最主要的缺点是会限制让你不能使用后期MySQL服务端提供所有的数据库高级特性。比如,PDO不允许使用MySQL支持的多语句执行。

  • 连接建立

    连接是通过创建 PDO 基类的实例而建立的。不管使用哪种驱动程序,都是用 PDO 类名。构造函数接收用于指定数据库源(所谓的 DSN)以及可能还包括用户名和密码(如果有的话)的参数。

    $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
    
  • 连接销毁

    连接数据成功后,返回一个 PDO 类的实例给脚本,此连接在 PDO 对象的生存周期中保持活动。要想关闭连接,需要销毁对象以确保所有剩余到它的引用都被删除,可以赋一个 NULL 值给对象变量。如果不明确地这么做,PHP 在脚本结束时会自动关闭连接。

  • 持久连接

    很多 web 应用程序通过使用到数据库服务的持久连接获得好处。持久连接在脚本结束后不会被关闭,且被缓存,当另一个使用相同凭证的脚本连接请求时被重用。持久连接缓存可以避免每次脚本需要与数据库回话时建立一个新连接的开销,从而让 web 应用程序更快。

    $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
        PDO::ATTR_PERSISTENT => true
    ));
    

    注意:在使用表锁及事务的情况下,最好还是不要使用持久化的数据库连接。在持久连接中使用数据表锁时,如果脚本不管什么原因无法释放该数据表锁,其随后使用相同连接的脚本将会被持久的阻塞。

  • 事务与自动提交

    事务通常是通过把一批更改"积蓄"起来然后使之同时生效而实现的;这样做的好处是可以大大地提供这些更改的效率。换句话说,事务可以使脚本更快,而且可能更健壮。

    不幸的是,并非每种数据库都支持事务,因此当第一次打开连接时,PDO 需要在所谓的"自动提交"模式下运行。自动提交模式意味着,如果数据库支持,运行的每个查询都有它自己的隐式事务,如果数据库不支持事务,则没有。如果需要一个事务,则必须用 PDO::beginTransaction() 方法来启动。如果底层驱动不支持事务,则抛出一个 PDOException 异常(不管错误处理设置是怎样的,这都是一个严重的错误状态)。一旦开始了事务,可用 PDO::commit() 或 PDO::rollBack()来完成,这取决于事务中的代码是否运行成功。

    开启一个显示事务,当脚本结束或连接即将被关闭时,如果尚有一个未完成的事务,那么 PDO 将自动回滚该事务。这种安全措施有助于如果没有显式地提交事务,在脚本意外终止时避免出现不一致的情况,那么假设是某个地方出错了,所以执行回滚来保证数据安全。

    比如我们通常会在try语句里开启事务,完成业务逻辑,并提交事务,而在异常捕获catch语句中回滚事务。

  • 预处理语句

    预处理语句有两个好处:

    1、查询仅需解析一次,但可以用不同的参数执行多次。数据库查询是要经过语句分析、编译、优化、执行,而预处理语句可以避免重复分析、编译、优化时间,使得占用更少资源并运行的更快。

    2、提供给预处理语句的参数不需要用引号,驱动程序会自动处理,可以确保SQL注入安全问题。当然sql语句存在由用户输入的部分,那么也需要进行转义,否则仍然存在注入问题。

    预处理语句可以使用占位符:? 或者 :name,:value

    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
    
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':value', $value);
    
    // 插入一行
    $name = 'one';
    $value = 1;
    $stmt->execute();
    
    //  用不同的值插入另一行
    $name = 'two';
    $value = 2;
    $stmt->execute();
    
    
    //占位符:?
    $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
    
    $stmt->bindParam(1, $name);
    $stmt->bindParam(2, $value);
    
    // 插入一行
    $name = 'one';
    $value = 1;
    $stmt->execute();
      
    $stmt = $dbh->prepare("SELECT * FROM REGISTRY where id = ?");
    
    if($stmt->execute(array($_GET['ids']))){
        while ($row = $stmt->fetch()) {
            print_r($row);
        }            
    }
    
  • POD驱动

    PDO的MySQL驱动并不是一套API,至少从PHP程序员的角度来看是这样的。实际上,PDO的MySQL驱动处于PDO自己的下层,提供了特定的Mysql功能。程序员直接调用PDO的API,而PDO使用了PDO的MySQL驱动完成与MySQL服务器端的交互。PDO的MySQL驱动是众多PDO驱动中的一个。其他可用的PDO驱动包括Firebird,PostgreSQL等等。

    • MS SQL Server
    • Firebird
    • IBM DB2
    • MySQL
    • Oracle
    • PostgreSQL
    • SQLite等

各数据库系统对应的扩展

有OCI8(oracle)、DB2、Firebird、MongoDB、PostgreSQL、SQLite3、tokyo_tyrant等等主流数据库

PHP中的数据库连接持久化 - 知乎