`
hitluobin
  • 浏览: 14292 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

PHP统一的数据访问接口PDO介绍

阅读更多
统一的数据访问接口PDO
PDO(PHP Data Objects) 扩展为 PHP 访问数据库定义了一个轻量级的、一致性的接口,它提供了一个数据访问抽象层,这样,无论使用什么数据库,用户都可以通过统一的函数执行来查询和获取数据。注意,你并不能使用 PDO 扩展本身执行任何数据库操作,必须使用一个 database-specific PDO driver (针对特定数据库的 PDO 驱动)访问数据库服务器。
目前 PDO 支持如表1中数据库操作接口:
驱动程序名 所支持的数据库服务器
PDO_DBLIB FreeTDS / Microsoft SQL Server / Sybase
PDO_FIREBIRD Firebird/Interbase 6
PDO_IBM IBM DB2
PDO_INFORMIX IBM Informix Dynamic Server
PDO_MYSQL MySQL 3.x/4.x/5.x
PDO_OCI Oracle Call Interface
PDO_ODBC ODBC v3 (IBM DB2, unixODBC and win32 ODBC)
PDO_PGSQL PostgreSQL
PDO_SQLITE SQLite 3 and SQLite 2

PDO 并不提供数据库抽象,它并不会重写 SQL 或提供数据库本身缺失的功能,如果用户需要这种功能,就必须使用一个更加成熟的抽象层。PDO 是随 PHP 5.1 发行,在PHP 5.0的 PECL 扩展中也可以使用。PDO 需要 PHP 5 核心面向对象特性的支持,所以它无法运行于之前的PHP 版本。
PDO 的安装部署方法将会在后面的章节介绍,此处先介绍 PDO 的使用。
连接和连接管理
数据库连接的建立可以通过创建一个 PDO 基类的实体实现,开发人员不用关心需要使用的是那个驱动,在代码中只需要使用 PDO 的类名。构造函数接受一个参数来表明数据源(也就是通常所知的 DSN)。另外还有三个参数是可选的,如果数据库服务器的连接需要提供用户名和密码,则需要在构造函数中指定;在该构造函数中,同时还可以通过第三个可选参数传递连接类型等的信息。
清单 7. 建立 PDO 连接(以 DB2 Server为例)
<?php
function Connect()
{
try{
$dbh = new PDO(‘odbc:test’,‘user’,‘password’,
array(PDO_ATTR_PERSISTENT =) true));
} catch(PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
die();
}
return $dbh;
}
?>

odbc:test 告诉 PDO 它所应该使用的 ODBC 驱动程序,并且应该使用 "test" 数据库。如果使用一个驱动程序管理器,那么可以用一个 ODBC 级数据源名称替代 "test"。在冒号字符之后可以指定任何有效的 ODBC 数据源连接字符串。接下来分别是用来连接数据库的用户名和密码。通过设定 PDO_ATTR_PERSISTENT 的值为 true 可以建立一个到数据库的持久连接,默认情况下不指定此参数建立的连接在脚本运行完毕或者所有对该 $dbh 的应用都被是释放的时候连接就会被断开。在某些情况应用程序的设计者只希望建立一次连接,以后对该数据库所有的访问操作都通过该连接实现。这时候就可以建立持久连接,持久连接建立后会被缓存并且在其他的数据库操作脚本访问该数据源的时候被重用。
断开连接
默认情况下,当建立的连接是非持久连接时候,当脚本结束时候连接将会断开,也可以通过显性的将 $dbh 变量设置为 null 来断开连接。
清单 8. 断开 PDO 连接
<?php
function Disconnect($dbh)
{
$dbh = null;
}
?>


执行数据库操作
建立了与数据库的连接之后就可以对数据库进行 SQL 查询操作,对于无返回结果集的数据库操作(例如删除,更新,插入等) PDO 通过一个统一的函数 exec() 来实现,这个函数的返回值通常是数据库操作影响的行数,以删除为例,函数的返回结果是删除的行数。而对于需要返回数据结果集的查询操作则通过 query() 函数来实现。它将返回一个 PDOStatement 类型的结果集合。对于 PDOStatement 类型的结果集可以用它的各种操作方法(例如 fetch() 等)来操作结果集里面的数据。
清单 9. 执行数据库操作
<?php
//issues a SQL statement and returns the number of affected rows.
function Execute($execStr)
{
try{
$dbh = Connect();//引用清单1中的方法
$result = $dbh->exec($execStr);
} catch (Exception $e) {

}
return $result;
}
//issues a SQL statement and returns a result set.
function Query($queryStr)
{
try{
$dbh = Connect();//引用清单1中的方法
$result = $dbh->query($queryStr);
} catch (Exception $e) {
}
return $result;
}
?>

事务和自动提交
PDO 的事务操作以自动提交模式运行,也就是说如果数据库支持事务,那么所运行的每一个查询都有它自己的隐式事务,如果数据库不支持事务,每个查询就没有这样的事务。如果需要启动一个事务操作,必须使用 PDO::beginTransaction() 方法来启动。这里需要注意的是:如果底层驱动程序不支持事务,那么将抛出一个 PDOException。在一个事务中,可以使用 PDO::commit() 或 PDO::rollBack() 来结束该事务,这取决于事务中运行的代码是否成功。
清单 10. 运用事务操作进行批处理
<?php
//issues a set of SQL statement during a transaction
function Execute (array $tranStr)
{
try{
$dbh = Connect();//引用清单1中的方法
$dbh->beginTransaction();
foreach($transStr as $stateStr)
{
$dbh->exec($stateStr);
}
$dbh->commit()
} catch (Exception $e) {
$dbh->rollBack();
}
return $result;
}
?>

在上面的函数中所要执行的一系列 SQL 命令包括在 beginTransaction() 和 commit() 调用中,可以保证在更改完成之前,其他人无法看到更改。如果发生了错误,catch 块可以回滚事务开始以后发生的所有更改。这样可以有效的保证数据的一致性,在需要同步进行操作的数据更新中有重要应用。当脚本结束或当一个连接即将被关闭时,如果有一个未完成的事务,那么 PDO 将自动回滚该事务。
预处理语句
首先需要解释一下预处理语句,通常将预处理语句看作要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。以运行一个重复插入数据为例,当往一个表中反复插入不同的数据的时候,使用预处理语句只需要编译一次,每次插入的时候只需要将变量用具体的参数取代即可。这可以在很大程度上提高数据库的性能。大部分成熟的数据库都支持预处理语句,即使驱动程序不支持预处理语句,PDO 也将仿真预处理语句。
清单 11. 使用预处理语句
<?php
$dbh = Connect();
$prepareStatement = $dbh->prepare(“INSERT INTO STUDENT (id,name) VALUES (:id,:name)”);

//bind the placeholder with a specify variable.
$prepareStatemnet->bindParam(‘:id’, $id);
$prepareStatement->bindParam(‘:name’, $name);

//insert records.
$id = ‘1’;
$name = ‘user1;
$prepareStatement->execute();
$id = ‘2’;
$name = ‘user2;
$prepareStatement->execute();
?>

回页首
示例程序:一个简单的网络连通性测试工具
在这个简单的示例程序中,使用 Perl 编写一个检查指定的服务器是否可以通过操作系统 ping 命令测试网络连通的函数,并通过 PHP 调用该方法获取测试结果,同时将测试的结果存入基于 DB2 的数据库中。在这个基于 WEB 的示例程序中,对于测试服务器网络是否可连接的 Perl 语言代码在附件的实例代码中,读者可以下载阅读。本文将不对该部分代码做解释,而将主要的精力放在描述 PHP 调用 Perl 代码的方法和 PDO 操作数据库的方法上。读者可以在本文的代码下载中获取到完整的该程序的源代码。
开发环境的搭建
本演示例程由数个样本程序组成,并使用了下列组件及开发测试工具:
操作系统:RedHat Enterprise Linux Server 5.0
WEB 服务器:Apache 2.2.8
数据库服务器:DB2 Server Enterprise Edition 9
PHP:5.0.0/5.2.6
Perl:5.8.0
对于 PHP 和 Apache 的安装部署在本文中不做重复介绍,以下仅介绍 PDO 和 Perl 扩展的安装与部署方法。
PHP Perl扩展的安装与部署
PHP 的 Perl 扩展可以在 PECL 的网站http://pecl.php.net/package/perl获得下载。为了正确安装和使用该扩展,操作系统的软件环境必须满足以下需求:
PHP 5.0.0 RC2 以上版本
Perl 5.8.0 以上版本
编译扩展文件,PHP_PREFIX 和 PERL_PREFIX 必须指向 PHP 和 Perl 的安装路径。
#export PHP_PREFIX="/usr"
#export PERL_PREFIX="/usr"
#$PHP_PREFIX/bin/PHPize
#./configure --with-Perl=$PERL_PREFIX --with-PHP-config=$PHP_PREFIX/bin/PHP-config
#make

安装(这一步需要根用户特权)
#make install

在 php.ini 中添加 Perl 扩展 (这一步需要根用户特权)
extension=Perl.so

PDO 扩展的安装部署
PHP 5.1 发布时附带了 PDO,但是也可以通过 PECL 这个 PHP 扩展库来结合使用 PDO 和 (1) PHP 5.0.3 及以上版本的安装。
在示例应用程序的开发中,所使用的是一个 DB2 数据库服务器。需要注意的一点是在安装PDO 时需要 ODBC 驱动,这就需要在本地安装有 DB2 管理客户机,否则编译将失败。
在 PHP 5.0.3 及以上版本上通过 PECL 进行安装
默认情况下,PHP 将安装 "PEAR" 包管理系统。为了成功地安装 PDO,需要升级到 PEAR 1.3.5(需要跟用户特权);使用以下命令
#pear upgrade PEAR

接下来就可以安装 PDO 了(同样需要根用户特权):
#pear install PDO
安装完 PDO 核心后,为了使之生效,需要在 php.ini 文件中添加以下内容:
extension=pdo.so

接下来需要安装用于 PDO 的 ODBC 驱动程序
#pear install PDO_ODBC 

按照提示输入 ODBC 驱动程序的类型和驱动程序的位置,在示例程序中使用的是 DB2 服务器,如果采用 DB2 的默认安装选项,可以直接输入 ibm-db2,如果选择了不同的安装位置,就要用实际的位置替换 /home/db2inst1/sqllib。由于 PEAR 不会为用户配置 PECL 扩展,因此在安装完成后需要将驱动程序添加到 php.ini 文件中,从而在PHP中正确加载驱动程序。确保将下面的内容添加在之前所添加的 pdo.so 这一行之后,否则 PHP 将不能正确地初始化。
extension=pdo_odbc.so
(2) PHP 5.1及以上版本的安装
PHP 5.1 发布时附带了 PDO,为获得 DB2 支持,只需在编译 PHP 时将下面的开关添加到配置行。
#tar xzvf php-5.2.6.tar.gz
#cd php-5.2.6
#./configure –with-pdo-odbc=ibm-db2,/home/db2inst1/sqllib --with-apxs2=/usr/sbin/apxs
#make
#make install

安装完毕后,应该完全重新启动 WEB 服务器,以确保 PHP 装载新的扩展,这样就可以开始使用 PDO 了。如果您使用的是 UNIX 平台,那么需要获得 DB2 客户机的 DB2 实例环境,以便正确地初始化,可以通过运行命令 source /home/db2inst1/sqllib/db2profile 来完成。
示例程序
该示例程序的流程和结构如下图所示,下面将分别介绍各个部分的功能及实现方法。读者可以在本文附带的示例代码中

图 1. 示例程序总体结构

测试服务器连通性的 Perl 模块(Connectivity Test Module)
代码文件:SERVERCHECK.pm
该模块采用 Perl 编写,使用 Perl 的系统调用函数 system() 执行 ping 命令,将标准输出输入到日志文件中,然后利用 Perl 的正则处理能力校验文件中的内容,从来判断服务器的是否能通过 ping 命令检测远端服务器的网络是否连通。在该函数中所调用的validate_cmd_response()函数会调用system()系统函数并捕获标准输出,同时验证标准输出中是否匹配指定字符串。

清单 12. 判断远端服务器网络连接性
sub server_is_connective {
my( $class) = shift @_;
my( $serverIp ) = @_;
my( $pingOption,$validValue);
$pingOption = '-c 2';
$validValue = ("2 packets transmitted, 2 received, 0% packet loss");
my($rtnValue) = &validate_cmd_response("ping $pingOption $serverIp",$validValue);
print $rtnValue;
}
sub validate_cmd_response{
my( $cmd,$pValid) = @_;
if( $cmd ){
my ( @stdoutValue ) = &x_execute_cmd( $cmd );
if ( grep( /$pValid/i, @stdoutValue ) ){
return 1;
}
}
return 0;
}


PHP-Perl函数连接器(PHP-Perl Connector)
代码文件:Connector.php
该部分实现一个是从 Perl 接口向 PHP 接口转化的连接方法,在该部分中将 Perl 类中的方法转化成PHP函数。

清单 13. PHP 调用 Perl
<?php
public function php2perl($func_name,array $para_array)
{
$func_str = $func_name."(\"\",";
$conn_str = "";
foreach($para_array as $para)
{//add all parameters
$func_str.= $conn_str."\"".$para."\"";
$conn_str = ",";
}
$func_str .= ");";
try {
ob_start();
$perl = new Perl();
//push the complete directory of perl file into @INC variable
$perl->eval('push(@INC,"/web/www.domain.com/docs/sample");');
$perl->eval('use SERVERCHECK');
$result = $perl->eval("SERVERCHECK::$func_str");
$out = ob_get_contents();
ob_end_clean();
} catch(PerlException $excep){
echo "Perl error".$excep->getMessage()."\n";
$out = "Perl error";
}
return $out;
}
?>



在实例代码中只给出了一个转换,如果 Perl 代码中有其他的接口,也可以按照相同的方式将其转化为 PHP 接口。只要在方法中给出要调用的 Perl 方法的名字,并将要传递的参数放到一个数组中作为第二个参数,然后调用 php2perl() 方法就可以实现。在所定义的 PHP 函数 is_server_connective() 中,通过直接调用 php2perl() 函数,可以直接获得 Perl 函数 server_is_connective() 的返回结果。

清单 14. 使用php2perl的方法将Perl函数加以封装
public function is_server_connective($server)
{
$para = array($server);
$result = $this->php2perl('server_is_connective',$para);
return $result;
}



数据库操作模块(DB Operation Module)
代码文件:
PdoOpt.php(PDO 通用操作类)
GeneralDbOpt.php(数据库通用操作类)
ServerData.php(serversample 表操作类)
该模块实现应用程序跟 DB2 服务器的通信,通过这个部分可以将数据库中需要测试网络连接的服务器信息(主机名和地址)查询出来,在完成服务器连通性测试之后将测试结果更新回数据库中。在这里将 PDO 的基本操作单独抽象为一个类 PdoOpt,当需要更换数据库的时候可以在该文件中更改相应的数据库驱动等信息即可。基于此类可以建立出对数据库数据进行增删改查等基本的操作的数据库通用操作类 GeneralDbOpt,下面的代码演示了该类使用 PdoOpt 类执行数据查询的方法。

清单 15. 通过 PdoOpt 从指定表中查找指定id的数据结果
public function select($table,$select_id)
{
$sel_str = "select * from $table ";
if($select_id !== ""&& $select_id !== null) 
{
$sel_str .= " where id =".$select_id;
}
try{
if($result = $this->pdoOpt->Query($sel_str))
{
$rtn_value = $result->fetch(PDO::FETCH_ASSOC);
}
} catch(Exception $e) {
echo $e->getMessage();
}
return $rtn_value;
}



在此类基础之上构建对于具体表的操作方法。应用中以操作 serversample 表为例实现了一个 ServerData 类。所有对该表的操作都在该类中实现。以获取数据库中所有的服务器信息为例演示如何使用 GeneralDbOpt 类

清单 16. 从数据库中获取服务器列表
public function get_server_list()
{
$fields = array('id','name');
$tables = array ($this->table);
return $this->general_db_opt->select_all($tables,$fields,'');
}



数据库说明:数据库表中只有一个简单的演示用表 serversample,该表中有 id,name,ip,status 四个字段,分别代表服务器的标识,主机名,IP地址和状态信息。具体信息可以参看附件中的数据库表结构信息。
页面展现模块(Web View)
为了更好更清晰的展现该示例应用程序的逻辑结构,在该部分简单采用了 Smarty 的模板技术,避免将PHP 代码夹杂到 HTML 代码中。只使用该技术将数据库中查出的服务器信息呈现到页面上,在 Smarty 的网站 http://smarty.php.net/ 可以下载安装该引擎。

清单 17. Smarty 简单示例
<?php
require('/usr/local/lib/php/Smarty/Smarty.class.php');
define('_SMARTY_ROOT','/web/www.domain.com/Smarty');
$smarty = new Smarty();
$smarty->template_dir = _SMARTY_ROOT."/templates";
$smarty->compile_dir = _SMARTY_ROOT."/templates_c";
$smarty->cache_dir = _SMARTY_ROOT."/cache";
$smarty->config_dir = _SMARTY_ROOT."/configs";
$smarty->right_delimiter = '}>';
$smarty->left_delimiter = '<{';
?>



应用程序逻辑
首先获取服务器的信息并显示到页面上,可以通过 get_server_list() 方法获取到服务器的信息,然后将其赋值给 server_info 变量,Smarty 在页面上控制如何展现这些服务器信息。

清单 18. 从数据库中获取所有服务器的信息并在 WEB 页面呈现
<?php
require('main.php');
require('ServerData.php');
$serverData = new ServerData();
$server_info = $serverData->get_server_list();
$smarty->assign('server_info',$server_info);
$smarty->display('serverping.tpl');
?>



当点击页面上的 Test 按钮时候会获取当前按钮所指定的服务器的 id,从而获得所需要测试连通性的服务器信息,通过调用 connector 的方法测试,测试完毕后调用 ServerData 的更新方法将测试结果更新进数据库中指定 id 的服务器信息中。

清单 19. 从 PHP 端测试服务器连通性并将数据更新至数据库中
<?php
require_once('Connector.php');
require_once('ServerData.php');
require('main.php');

$server_id = $_GET["serverid"];
$serverData = new ServerData();
$serverData->get_server_info($server_id); //get server ip information
$server_ip = $serverData->ip;
$connector = new Connector();
$result = $connector->is_server_connective($server_ip); //test server connectivity

if($result)
{
//print test result and update server information
}
else
{
//print test result and update server information
}
$serverData->update_server_info($server_id);//update test result into database
echo $rtn_str;
?>



当点击了每行右侧的 Test 按钮后,可以获得所测试的服务器 IP 地址的网络连接是否成功:


结束语
至此,本文已经介绍了基于 PHP 5 面向对象特性的两个 PECL 扩展的安装部署及使用方法,同时通过示例演示程序,基本介绍了这两个 PECL 扩展的具体应用方法。基于 PHP 5 面向对象新特性的诸多 PECL 扩展给 PHP 开发带来极大的便捷,也大大增强了 PHP 的语言扩展功能。如果您想在其他的环境下部署您的应用程序或者获得这两个基于 PECL 的扩展更为详细的信息,可以通过访问 PHP 和 PECL 的网站来获得这两个扩展的详细手册与说明。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics