PHP 5 数据对象 (PDO) 抽象层与 Oracle(2)
连接管理
目前,PDO 完全没有执行自己的任何连接管理,因此每个“新 PDO”调用都会建立一个新的数据库连接。该连接在 $dbh 变量越界时,或者当您为其指定 NULL 值时会被释放。
<?php
try {
$dbh = new PDO("OCI:dbname=accounts;charset=UTF-8", "scott", "tiger");
} catch (PDOException $e) {
echo "Failed to obtain database handle " .$e->getMessage();
exit;
}
// 在此处对数据库执行一些操作
// ...
// 现在完成,释放该连接
$dbh = null;
?>
计划在不久的将来为 PDO 增加连接缓存功能;就当前的 oci8 扩展而言,会重用与现有服务器的连接,并且在这些连接中,还会重用闲置的登录。当在缓存连接模式中运行时,如上面的代码段所示释放 $dbh 时会将该登录标记为可由其他连接重用。
如果您使用 ODBC 驱动程序访问 Oracle,则可能会很高兴地注意到,默认情况下 PDO_ODBC 驱动程序支持 ODBC 连接池。
使用 PDO
了解一个编程 API 的最好方式就是使用它,因此我们来看一下附带的这个演示,以了解如何进行批次更新(代码如下)。
<?php
// Create a PDO database handle object
// the 'oci:' string specifies that the OCI driver should be used
// you could use 'oci:dbname=name' to specify the database name.
// The second and third parameters are the username and password respectively
$dbh = new PDO('oci:', 'scott', 'tiger');
// Create a test table to hold the data from credits.csv
$dbh->exec("
CREATE TABLE CREDITS (
extension varchar(255),
name varchar(255)
)");
// start a transaction
$dbh->beginTransaction();
// prepare to insert a large quantitiy of data
$stmt = $dbh->prepare("INSERT INTO CREDITS (extension, name) VALUES (:extension, :name)");
// bind the inputs to php variables; specify that the data will be strings
// with a maximum length of 64 characters
$stmt->bindParam(':extension', $extension, PDO_PARAM_STR, 64);
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
// Open the .csv file for import
$fp = fopen('credits.csv', 'r');
while (!feof($fp)) {
list($extension, $name) = fgetcsv($fp, 1024);
$stmt->execute();
}
fclose($fp);
// Commit the changes
$dbh->commit();
?>
既然我们已经成功连接到了 Oracle,那么现在就可以创建一个表来保存一些数据了。对于此示例,我们使用一些 PHP 扩展及其作者,并将这些内容输入一个数据库中。数据库句柄对象的 exec() 方法可用来发出不会返回结果集的快速一次性查询,因此我们在这里使用该方法来发出 CREATE TABLE 查询。
为了使得示例更自然,我从 PHP 源代码中抽取了扩展及其作者的信息,并将其存储到了一个 CSV 文件中(请参见“相关附件:credits.csv”)。这就代表一个常见情形:从 CSV 文件批次导入数据。在我们的示例中,我们充分利用了 Oracle 的预处理语句和绑定参数,以获得一个高效的数据导入脚本。在讲述该示例之前,有必要了解一下 PDO 处理事务的方式。
PDO 中的事务处理
Oracle 具有一个敏感的默认操作模式:当您进行连接时,将会位于一个隐式事务处理中,在提交事务之前其中的更改不会完全生效。除了事务处理的标准优点(原子性、一致性、隔离性、可持久性 - ACID)之外,数据库服务器在执行每次更新之后还不需要重新构建索引和其他内部结构;它可以延迟到提交之后进行。这样会加速代码的执行。Oracle 这点确实很好。
但不幸的是,并非每个数据库供应商都支持事务处理,并且因为 PDO 旨在以一种相对可移植的方式支持这些事务处理,所以它默认情况下以自动提交模式运行。启用自动提交模式后,数据库驱动程序会隐式提交每个成功的更新。当您调用 $dbh->beginTransaction() 时,就会请求关闭自动提交,直到调用 $dbh->commit() 或者 $dbh->rollBack() 才会重新启用,具体取决于您的代码是怎样编写的。如果基础驱动程序不支持事务处理,则会抛出一个 PDOException。
如果发生了问题并且 PHP 出错,您的脚本将退出并且事务处于待批状态;或者您关闭数据库句柄时,PDO 会自动针对任何待批的事务调用 $dbh->rollBack()。此行为会减少向数据库中提交可能未定义或者已损坏数据的可能性,这是用于处理已放弃事务的标准语义。
预处理语句、存储过程
PDO 支持使用 Oracle 样式命名的占位符语法将变量帮定到 SQL 中的预处理语句(与 oci8 扩展中的 ocibindbyname() 类似)。PDO 还为其他数据库(如 ODBC)提供了命名占位符模拟,甚至可以为生来就不支持该概念的数据库(如 MySQL)模拟预处理语句和绑定参数。这是 PHP 向前迈进的积极一步,因为这样可以使开发人员能够用 PHP 编写“企业级”的数据库应用程序,而不必特别关注数据库平台的能力。
使用 PDO 预处理语句非常简单,调用数据库句柄的 prepare() 方法即可。它会返回一个语句句柄对象,然后您可以使用该对象来绑定参数和执行语句。在此示例中,我们将要定义两个命名占位符,“:extension”和“:name”,这两个占位符分别与 .CSV 文件中的 PHP 扩展名称和其中一个作者的姓名相对应。
$stmt = $dbh->prepare("INSERT INTO CREDITS (extension, name) VALUES (:extension, :name)");
预处理了语句之后,我们使用 bindParam() 方法来将这些命名参数分别与 PHP 变量名称“$extension”和“$name”相关联(这与 ocibindbyname() 类似)。我们还会通知 Oracle,这些数据将要格式化为字符串,最大长度为 64 个字符。
$stmt->bindParam(':extension', $extension, PDO_PARAM_STR, 64);
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
我们现在即准备好插入数据了 - 我们只需要打开该 CSV 文件,并从中获取数据即可。通过使用 fopen() 和 fgetcsv() 函数可以相当简单地完成此操作。然后,我们可以使用 PHP list() 构造函数直接将 CSV 的列指定给变量“$extension”和“$name”。因为这些变量已经绑定到了语句中,所以我们现在要做的只是调用该语句对象的 execute() 方法使其执行插入。这种方式既方便又快捷 - 在事务处理时每个迭代循环只有两行。到达文件尾时,我们就可以立即使用数据库句柄的 commit() 方法来提交
目前,PDO 完全没有执行自己的任何连接管理,因此每个“新 PDO”调用都会建立一个新的数据库连接。该连接在 $dbh 变量越界时,或者当您为其指定 NULL 值时会被释放。
<?php
try {
$dbh = new PDO("OCI:dbname=accounts;charset=UTF-8", "scott", "tiger");
} catch (PDOException $e) {
echo "Failed to obtain database handle " .$e->getMessage();
exit;
}
// 在此处对数据库执行一些操作
// ...
// 现在完成,释放该连接
$dbh = null;
?>
计划在不久的将来为 PDO 增加连接缓存功能;就当前的 oci8 扩展而言,会重用与现有服务器的连接,并且在这些连接中,还会重用闲置的登录。当在缓存连接模式中运行时,如上面的代码段所示释放 $dbh 时会将该登录标记为可由其他连接重用。
如果您使用 ODBC 驱动程序访问 Oracle,则可能会很高兴地注意到,默认情况下 PDO_ODBC 驱动程序支持 ODBC 连接池。
使用 PDO
了解一个编程 API 的最好方式就是使用它,因此我们来看一下附带的这个演示,以了解如何进行批次更新(代码如下)。
<?php
// Create a PDO database handle object
// the 'oci:' string specifies that the OCI driver should be used
// you could use 'oci:dbname=name' to specify the database name.
// The second and third parameters are the username and password respectively
$dbh = new PDO('oci:', 'scott', 'tiger');
// Create a test table to hold the data from credits.csv
$dbh->exec("
CREATE TABLE CREDITS (
extension varchar(255),
name varchar(255)
)");
// start a transaction
$dbh->beginTransaction();
// prepare to insert a large quantitiy of data
$stmt = $dbh->prepare("INSERT INTO CREDITS (extension, name) VALUES (:extension, :name)");
// bind the inputs to php variables; specify that the data will be strings
// with a maximum length of 64 characters
$stmt->bindParam(':extension', $extension, PDO_PARAM_STR, 64);
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
// Open the .csv file for import
$fp = fopen('credits.csv', 'r');
while (!feof($fp)) {
list($extension, $name) = fgetcsv($fp, 1024);
$stmt->execute();
}
fclose($fp);
// Commit the changes
$dbh->commit();
?>
既然我们已经成功连接到了 Oracle,那么现在就可以创建一个表来保存一些数据了。对于此示例,我们使用一些 PHP 扩展及其作者,并将这些内容输入一个数据库中。数据库句柄对象的 exec() 方法可用来发出不会返回结果集的快速一次性查询,因此我们在这里使用该方法来发出 CREATE TABLE 查询。
为了使得示例更自然,我从 PHP 源代码中抽取了扩展及其作者的信息,并将其存储到了一个 CSV 文件中(请参见“相关附件:credits.csv”)。这就代表一个常见情形:从 CSV 文件批次导入数据。在我们的示例中,我们充分利用了 Oracle 的预处理语句和绑定参数,以获得一个高效的数据导入脚本。在讲述该示例之前,有必要了解一下 PDO 处理事务的方式。
PDO 中的事务处理
Oracle 具有一个敏感的默认操作模式:当您进行连接时,将会位于一个隐式事务处理中,在提交事务之前其中的更改不会完全生效。除了事务处理的标准优点(原子性、一致性、隔离性、可持久性 - ACID)之外,数据库服务器在执行每次更新之后还不需要重新构建索引和其他内部结构;它可以延迟到提交之后进行。这样会加速代码的执行。Oracle 这点确实很好。
但不幸的是,并非每个数据库供应商都支持事务处理,并且因为 PDO 旨在以一种相对可移植的方式支持这些事务处理,所以它默认情况下以自动提交模式运行。启用自动提交模式后,数据库驱动程序会隐式提交每个成功的更新。当您调用 $dbh->beginTransaction() 时,就会请求关闭自动提交,直到调用 $dbh->commit() 或者 $dbh->rollBack() 才会重新启用,具体取决于您的代码是怎样编写的。如果基础驱动程序不支持事务处理,则会抛出一个 PDOException。
如果发生了问题并且 PHP 出错,您的脚本将退出并且事务处于待批状态;或者您关闭数据库句柄时,PDO 会自动针对任何待批的事务调用 $dbh->rollBack()。此行为会减少向数据库中提交可能未定义或者已损坏数据的可能性,这是用于处理已放弃事务的标准语义。
预处理语句、存储过程
PDO 支持使用 Oracle 样式命名的占位符语法将变量帮定到 SQL 中的预处理语句(与 oci8 扩展中的 ocibindbyname() 类似)。PDO 还为其他数据库(如 ODBC)提供了命名占位符模拟,甚至可以为生来就不支持该概念的数据库(如 MySQL)模拟预处理语句和绑定参数。这是 PHP 向前迈进的积极一步,因为这样可以使开发人员能够用 PHP 编写“企业级”的数据库应用程序,而不必特别关注数据库平台的能力。
使用 PDO 预处理语句非常简单,调用数据库句柄的 prepare() 方法即可。它会返回一个语句句柄对象,然后您可以使用该对象来绑定参数和执行语句。在此示例中,我们将要定义两个命名占位符,“:extension”和“:name”,这两个占位符分别与 .CSV 文件中的 PHP 扩展名称和其中一个作者的姓名相对应。
$stmt = $dbh->prepare("INSERT INTO CREDITS (extension, name) VALUES (:extension, :name)");
预处理了语句之后,我们使用 bindParam() 方法来将这些命名参数分别与 PHP 变量名称“$extension”和“$name”相关联(这与 ocibindbyname() 类似)。我们还会通知 Oracle,这些数据将要格式化为字符串,最大长度为 64 个字符。
$stmt->bindParam(':extension', $extension, PDO_PARAM_STR, 64);
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
我们现在即准备好插入数据了 - 我们只需要打开该 CSV 文件,并从中获取数据即可。通过使用 fopen() 和 fgetcsv() 函数可以相当简单地完成此操作。然后,我们可以使用 PHP list() 构造函数直接将 CSV 的列指定给变量“$extension”和“$name”。因为这些变量已经绑定到了语句中,所以我们现在要做的只是调用该语句对象的 execute() 方法使其执行插入。这种方式既方便又快捷 - 在事务处理时每个迭代循环只有两行。到达文件尾时,我们就可以立即使用数据库句柄的 commit() 方法来提交
