PHP5中PDO使用---高效连接Mysql的PDO和ADODB是当今世界最快的数据库抽象类

jackxiang 2010-5-8 22:47 | |
PHP数据库抽象层与数据库抽象类
1 什么是数据库抽象层
2 常用的数据库抽象层
3 数据库抽象层ADODB-实例
[编辑本段]PHP数据库抽象层与数据库抽象类
  目前,在PHP的网站及众多书籍中,很少讲到数据库抽象层,有的PHP开发者虽然已做了几年开发工作,但似乎也没有意识到它的存在。
  很多人并不理解数据抽象的重要性,也不了解mysql或mysqli扩展与PDO的区别,PDO与ADODB又有什么区别。
  在本章中将讲述以下内容,通过学习,上面的问题都会迎刃而解。
   使用数据库抽象层的原因;
   数据库抽象层的发展;
   一些流行新抽象层的介绍;
   PDO数据库抽象层开发技术;
   ADODB数据库抽象层开发技术。
[编辑本段]1 什么是数据库抽象层
  使用数据库抽象层,意味着当从一个数据库系统向另一个数据库系统迁移时,几乎不用更改太多的程序代码,如将MS SQL Server迁移到MySQL。
  首先,代码规划必须规范,即整个系统使用同一个数据对象实例,并且使用同一个较好的数据库抽象层。如果有一天用户要求将Oracle切换到MySQL,则只需要改变系统的配置文件即可。
  在当今工业领域中,每个数据库开发商如微软、Oracle、MySQL,都有自己的一套SQL标准,它们声称是按照ANSI SQL92标准而增加自己的特性,以达到垄断或占领市场的目的。
  优秀的数据库抽象层,会根据我们现在使用的数据库自动调整一些SQL性能。当没有使用数据库本身特定的特性时,就不必更改太多的数据库连接和数据库SQL查询。
  使用数据库抽象层的其他好处是:其性质、概念简化了复杂的任务。因此,我们不必学习某个数据库系统的全新特性,而只用一个标准的抽象层的代码特性即可。
  虽然这是一种理想化,但随着技术的发展,相信数据库抽象层会为我们做更多的事。
  目前,使用PHP进行不同的数据库系统开发,这些系统很不相同,而许多数据库抽象层在PHP的层次有所不同,但彼此使用方法相当,它的发展无疑会提高开发效率。
  请看图17-1,观察有数据抽象层和没有数据抽象层的区别。
  数据库抽象层的主要性能指标是速度,由于数据库抽象层是额外的代码层,因为面向不同的架构与体系,因此有的效率较高,有的则相对比较慢些。
  如Metabase是PHP中较慢的一个数据抽象层,它使用C语言编写,因为它的设计与可移植性最高,而PDO和ADODB是当今世界最快的数据库抽象类。

  如果您非常关注系统的效率和性能,则可以按自己的基准,设置模拟环境,编写代码,测试每个数据库抽象层(类)的性能。
[编辑本段]2 常用的数据库抽象层
  目前,有4种主流数据库抽象层:Metabase、PEAR:DB、PDO及ADODB。
  从目前的应用来看,ADODB和PEAR:DB最受欢迎(因为PEAR是被捆绑在PHP目录中的,但PEAR:DB的效率问题一直引人诟病)。
  从PHP 5开始出现的PDO及ADODB(其中包括PDO、MySQLi的底层实现)已经逐渐普及。
  也有一些更新的抽象类值得一用,PEAR:MDB(现在的版本名称为PEAR:MDB2)已经将Metabase和PEAR:DB合并,并且效率较之从前有很大的提高。
[编辑本段]3 数据库抽象层ADODB-实例

  require ‘adodb/adodb.inc.php’;
  // Connect to the database
  $conn = &ADONewConnection(‘mysql’);
  $conn->connect(‘localhost’,'phpgems’,'phpgems1′,’phpgems’);
  // Send a SELECT query to the database
  $rs = $conn->execute(‘SELECT flavor, price, calories FROM _
  ice_cream’);
  // Check if any rows were returned
  if ($rs->RecordCount() > 0) {
  print “<table>”;
  print “<tr><TH>Ice Cream Flavor</TH><TH>Price per Serving</TH><TH>Calories per Serving</TH></TR>”;
  // Retrieve each row
  while (! $rs->EOF) {
  print “<tr><TD>{$rs->fields[0]}</TD><TD>{$rs->fields[1]}</TD><TD>{$rs->f ields[2]}</TD></TR>n”;
  $rs->MoveNext();
  }
  print “</table>”;
  } else {
  print “No results”;
  }

PDO是PHP 5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,什么 php_mysql.dll、php_pgsql.dll、php_mssql.dll、php_sqlite.dll等等扩展来连接MySQL、 PostgreSQL、MS SQL Server、SQLite。
PDO(PHP Data Object) 是PHP 5新出来的东西,在PHP 6都要出来的时候,PHP 6只默认使用PDO来处理数据库,将把所有的数据库扩展移到了PECL,那么默认就是没有了我们喜爱的php_mysql.dll之类的了。
【PDO是啥】
  PDO是PHP 5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,什么 php_mysql.dll、php_pgsql.dll、php_mssql.dll、php_sqlite.dll等等扩展来连接MySQL、PostgreSQL、MS SQL Server、SQLite,同样的,我们必须借助 ADOdb、PEAR::DB、PHPlib::DB之类的数据库抽象类来帮助我们,无比烦琐和低效,毕竟,php代码的效率怎么能够我们直接用C/C++写的扩展斜率高捏?所以嘛,PDO的出现是必然的,大家要平静学习的心态去接受使用,也许你会发现能够减少你不少功夫哦。
【安装PDO】
  我是在Windows XP SP2 上面,所以嘛,整个过程都是在Windows行进行的啦,至于Linux/FreeBSD 等平台,请自行查找资料设置安装。
我的是PHP 5.1.4,已经自带有了php_pdo.dll的扩展,不过需要稍微设置一下才能使用。
  打开 c:\windows\php.ini ,那是我的PHP配置文件,找到下面这行:
  extension_dir
  这个就是我们扩展存在的目录,我的PHP 5扩展是在:C:\php5\ext,那么我就把这行改成:
  extension_dir = "C:/php5/ext"
  然后再往php.ini下面找到:
  ;;;;;;;;;;;;;;;;;;;;;;
  ; Dynamic Extensions ;
  ;;;;;;;;;;;;;;;;;;;;;;
  下面有一堆类似 ;extension=php_mbstring.dll 的东西,这里就是PHP扩展加载的配置了,我们再最后面添加上我们PDO的扩展:
extension=php_pdo.dll
extension=php_pdo_mysql.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
extension=php_pdo_mssql.dll
extension=php_pdo_odbc.dll
extension=php_pdo_firebird.dll
;extension=php_pdo_oci8.dll
  各种PDO的驱动,能给加上的全给加上,不过后面的php_pdo_oci8.dll,因为我没有安装Oralce数据库,所以没有这个,就使用分号注释掉它。然后重启我们的Web服务器, IIS/Apache,我的是IIS,嘿嘿,表鄙视我,在Windows上,简单嘛。
  重启后,在我们Web服务器的文档目录下写一个phpinfo.php的文件,加上这些:
<?
 phpinfo();
?>
  然后打开我们可爱的浏览器:IE/FireFox,我的是FireFox 2.0,刚下载的,很爽,不怕流氓软件,哈哈。
  在浏览器里面输入:http://localhost/phpinfo.php,如果你的这个页面路径不一致,请自行输入。
  输出的内容中,如果你能够顺利的看到:
PDO
PDO support enabled
PDO drivers mysql, pgsql, sqlite, mssql, odbc, firebird
  后面有各种驱动的说明:PDO_Firebird,pdo_mssql,pdo_mysql,PDO_ODBC,pdo_pgsql,pdo_sqlite
  那么,恭喜你安装成功了,否则请仔细检查上面的步骤。
  【牛刀小小试】
  我用的是MySQL 4.0.26,但是我个人推荐大家使用 MySQL 4.1.x 或者 MySQL 5.0.x,因为那些版本有很多有趣的东西值得去学习。我们这里PDO需要连接的就是我的MySQL 4.0啦,如果你没有安装MySQL,请自行安装。我们建立好了MySQL,并且在test库里添加了表foo,包括 id,name,gender,time等四个字段。
  我们开始构造第一个PDO应用,建立一个pdo.php文件在Web文档目录下:
<?php
 $dsn = "mysql:host=localhost;dbname=test";
 $db = new PDO($dsn, 'root', '');
 $count = $db->exec("INSERT INTO foo SET name = 'heiyeluren',gender='男',time=NOW()");
 echo $count;
 $db = null;
?>
  不明白啥意思,俺们来慢慢讲讲。这行:
$dsn = "mysql:host=localhost;dbname=test";
  就是构造我们的DSN(数据源),看看里面的信息包括:数据库类型是mysql,主机地址是localhost,数据库名称是test,就这么几个信息。不同数据库的数据源构造方式是不一样的。
$db = new PDO($dsn, 'root', '');
  初始化一个PDO对象,构造函数的参数第一个就是我们的数据源,第二个是连接数据库服务器的用户,第三个参数是密码。我们不能保证连接成功,后面我们会讲到异常情况,这里我们姑且认为它是连接成功的。
$count = $db->exec("INSERT INTO foo SET name = 'heiyeluren',gender='男',time=NOW()");
echo $count;
  调用我们连接成功的PDO对象来执行一个查询,这个查询是一个插入一条记录的操作,使用PDO::exec() 方法会返回一个影响记录的结果,所以我们输出这个结果。最后还是需要结束对象资源:
$db = null;
  默认这个不是长连接,如果需要数据库长连接,需要最后加一个参数:array(PDO::ATTR_PERSISTENT => true) 变成这样:
$db = new PDO($dsn, 'root', '', array(PDO::ATTR_PERSISTENT => true));
  一次操作就这么简单,也许跟以前的没有太大区别,跟ADOdb倒是有几分相似。
  【继续了解】
  如果我们想提取数据的话,那么就应该使用数据获取功能。(下面用到的$db都是上面已经连接好的对象)
<?php
 foreach($db->query("SELECT * FROM foo")){
  print_r($row);
 }
?>
  我们也可以使用这种获取方式:
<?php
 $rs = $db->query("SELECT * FROM foo");
 while($row = $rs->fetch()){
  print_r($row);
 }
?>
  如果想一次把数据都获取到数组里可以这样:
<?php
$rs = $db->query("SELECT * FROM foo");
$result_arr = $rs->fetchAll();
print_r($result_arr);
?>
Array
([0] => Array(
 [id] => 1
 [0] => 1
 [name] => heiyeluren
 [1] => heiyeluren
 [gender] => 男
 [2] => 男
 [time] => 2006-10-28 23:14:23
 [3] => 2006-10-28 23:14:23
)
}
  我们看里面的记录,数字索引和关联索引都有,浪费资源,我们只需要关联索引的:
<?php
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
$rs = $db->query("SELECT * FROM foo");
$rs->setFetchMode(PDO::FETCH_ASSOC);
$result_arr = $rs->fetchAll();
print_r($result_arr);
?>
  看上面的代码,setAttribute() 方法是设置部分属性,主要属性有:PDO::ATTR_CASE、PDO::ATTR_ERRMODE等等,我们这里需要设置的是PDO::ATTR_CASE,就是我们使用关联索引获取数据集的时候,关联索引是大写还是小写,有几个选择:
  PDO::CASE_LOWER -- 强制列名是小写
  PDO::CASE_NATURAL -- 列名按照原始的方式
  PDO::CASE_UPPER -- 强制列名为大写
  我们使用setFetchMode方法来设置获取结果集的返回值的类型,同样类型还有:
  PDO::FETCH_ASSOC -- 关联数组形式
  PDO::FETCH_NUM -- 数字索引数组形式
  PDO::FETCH_BOTH -- 两者数组形式都有,这是缺省的
  PDO::FETCH_OBJ -- 按照对象的形式,类似于以前的 mysql_fetch_object()
  当然,一般情况下我们是使用PDO::FETCH_ASSOC,具体使用什么,按照你自己的需要,其他获取类型参考手册。
  除了上面这种获取数据的方式,还有这种:
<?php
$rs = $db->prepare("SELECT * FROM foo");
$rs->execute();
while($row = $rs->fetch()){
 print_r($row);
}
?>
  其实差不多啦。如果你想获取指定记录里一个字段结果的话,可以使用 PDOStatement::fetchColumn():
<?php
$rs = $db->query("SELECT COUNT(*) FROM foo");
$col = $rs->fetchColumn();
echo $col;
?>
  一般使用fetchColumn()来进行count统计或者某些只需要单字段的记录很好操作。
  简单的总结一下上面的操作:
  查询操作主要是PDO::query()、PDO::exec()、PDO::prepare()。PDO::query()主要是用于有记录结果返回的操作,特别是SELECT操作,PDO::exec()主要是针对没有结果集合返回的操作,比如INSERT、UPDATE、DELETE等操作,它返回的结果是当前操作影响的列数。PDO::prepare()主要是预处理操作,需要通过$rs->execute()来执行预处理里面的SQL语句,这个方法可以绑定参数,功能比较强大,不是本文能够简单说明白的,大家可以参考手册和其他文档。 获取结果集操作主要是:PDOStatement::fetchColumn()、PDOStatement::fetch()、PDOStatement::fetchALL()。PDOStatement::fetchColumn() 是获取结果指定第一条记录的某个字段,缺省是第一个字段。PDOStatement::fetch() 是用来获取一条记录,PDOStatement::fetchAll()是获取所有记录集到一个中,获取结果可以通过PDOStatement::setFetchMode来设置需要结果集合的类型。
  另外有两个周边的操作,一个是PDO::lastInsertId()和PDOStatement::rowCount()。PDO::lastInsertId()是返回上次插入操作,主键列类型是自增的最后的自增ID。PDOStatement::rowCount()主要是用于PDO::query()和PDO::prepare()进行DELETE、INSERT、UPDATE操作影响的结果集,对PDO::exec()方法和SELECT操作无效。
  【错误处理】
  如果程序中碰到错误咋办?我们这里描述PDO类的错误信息和异常处理。
  1. 面向对象的方式
  先看看如果连接错误等的处理,使用面向对象的方式来处理:
<?php
try {
 $db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
 $db = null;
} catch (PDOException $e) {
 print "Error: " . $e->getMessage() . "<br/>";
 die();
}
?>
  这里利用我们PHP 5面向对象的异常处理特征,如果里面有异常的话就初始化调用PDOException来初始化一个异常类。
  PDOException异常类的属性结构:
<?php
class PDOException extends Exception
{
 public $errorInfo = null; // 错误信息,可以调用 PDO::errorInfo() 或 PDOStatement::errorInfo()来访问
 protected $message; // 异常信息,可以试用 Exception::getMessage() 来访问
 protected $code; // SQL状态错误代码,可以使用 Exception::getCode() 来访问
}
?>
  这个异常处理类是集成PHP 5内置的异常处理类,我们简单的看一下PHP 5内置的异常处理类结构:
<?php
class Exception
{
 // 属性
 protected $message = 'Unknown exception'; // 异常信息
 protected $code = 0; // 用户自定义异常代码
 protected $file; // 发生异常的文件名
 protected $line; // 发生异常的代码行号
 // 方法
 final function getMessage(); // 返回异常信息
 final function getCode(); // 返回异常代码
 final function getFile(); // 返回发生异常的文件名
 final function getLine(); // 返回发生异常的代码行号
 final function getTrace(); // backtrace() 数组
 final function getTraceAsString(); // 已格成化成字符串的 getTrace() 信息
}
?>
  相应的,在代码中可以合适的调用 getFile() 和 getLine() 来进行错误定位,更方便的进行调试。
  2. 使用面向过程的方法
  先看代码:
<?
$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$rs = $db->query("SELECT aa,bb,cc FROM foo");
if ($db->errorCode() != '00000'){
 print_r($db->errorInfo());
 exit;
}
$arr = $rs->fetchAll();
print_r($arr);
$db = null;
?>
  PDO和PDOStatement对象有errorCode() 和 errorInfo() 方法,如果没有任何错误, errorCode() 返回的是: 00000 ,否则就会返回一些错误代码。errorInfo() 返回的一个数组,包括PHP定义的错误代码和MySQL的错误代码和错误信息,数组结构如下:
Array
(
 [0] => 42S22
 [1] => 1054
 [2] => Unknown column 'aaa' in 'field list'
)
  每次执行查询以后,errorCode() 的结果都是最新的,所以我们可以很容易自己控制错误信息显示。
  【简单总结】
  从上面的使用看出,PDO功能确实强大,另外还有一些内容我没有讲到,比如绑定参数、预处理、存储过程、事务处理等等功能。另外还有不同数据扩 DSN的构造,Oracle数据库自己很多特殊的东西,都需要深入去学习理解,这篇文章就只是简单的描述了一些入门知识,算是对PDO一个简单的了解吧。
来源:http://www.blogguy.cn/show-371-1.html
本章着重讲述PHP数据库抽象层与数据库抽象类。
目前,在PHP的网站及众多书籍中,很少讲到数据库抽象层,有的PHP开发者虽然已做了几年开发工作,但似乎也没有意识到它的存在。
很多人并不理解数据抽象的重要性,也不了解mysql或mysqli扩展与PDO的区别,PDO与ADODB又有什么区别。
在本章中将讲述以下内容,通过学习,上面的问题都会迎刃而解。
�0�1使用数据库抽象层的原因;
�0�1数据库抽象层的发展;
�0�1一些流行新抽象层的介绍;
�0�1PDO数据库抽象层开发技术;
�0�1ADODB数据库抽象层开发技术。
17.1什么是数据库抽象层
使用数据库抽象层,意味着当从一个数据库系统向另一个数据库系统迁移时,几乎不用更改太多的程序代码,如将MS SQL Server迁移到MySQL。
首先,代码规划必须规范,即整个系统使用同一个数据对象实例,并且使用同一个较好的数据库抽象层。如果有一天用户要求将Oracle切换到MySQL,则只需要改变系统的配置文件即可。
在当今工业领域中,每个数据库开发商如微软、Oracle、MySQL,都有自己的一套SQL标准,它们声称是按照ANSI SQL92标准而增加自己的特性,以达到垄断或占领市场的目的。
优秀的数据库抽象层,会根据我们现在使用的数据库自动调整一些SQL性能。当没有使用数据库本身特定的特性时,就不必更改太多的数据库连接和数据库SQL查询。
使用数据库抽象层的其他好处是:其性质、概念简化了复杂的任务。因此,我们不必学习某个数据库系统的全新特性,而只用一个标准的抽象层的代码特性即可。
虽然这是一种理想化,但随着技术的发展,相信数据库抽象层会为我们做更多的事。
目前,使用PHP进行不同的数据库系统开发,这些系统很不相同,而许多数据库抽象层在PHP的层次有所不同,但彼此使用方法相当,它的发展无疑会提高开发效率。
请看图17-1,观察有数据抽象层和没有数据抽象层的区别。
数据库抽象层的主要性能指标是速度,由于数据库抽象层是额外的代码层,因为面向不同的架构与体系,因此有的效率较高,有的则相对比较慢些。
如Metabase是PHP中较慢的一个数据抽象层,它使用C语言编写,因为它的设计与可移植性最高,而PDO和ADODB是当今世界最快的数据库抽象类。
1.JPG (20.89 KB)
2007-11-1 18:53
        (b)使用数据抽象层的PHP程序架构
图17-1
如果您非常关注系统的效率和性能,则可以按自己的基准,设置模拟环境,编写代码,测试每个数据库抽象层(类)的性能。
17.2常用的数据库抽象层
目前,有4种主流数据库抽象层:Metabase、PEAR:DB、PDO及ADODB。
从目前的应用来看,ADODB和PEAR:DB最受欢迎(因为PEAR是被捆绑在PHP目录中的,但PEAR:DB的效率问题一直引人诟病)。
从PHP 5开始出现的PDO及ADODB(其中包括PDO、MySQLi的底层实现)已经逐渐普及。
也有一些更新的抽象类值得一用,PEAR:MDB(现在的版本名称为PEAR:MDB2)已经将Metabase和PEAR:DB合并,并且效率较之从前有很大的提高。
我们先对现今常用的数据库抽象类的历史及它们的简要特点进行一一介绍。
17.2.1 PEAR:DB
PEAR:DB自2001年以来,存在于PEAR中,由于PEAR默认绑定在PHP目录中,基于这些原因,成为比较流行的数据库抽象层。PEAR:DB所支持的数据库系统包括:
�0�1Firebird
�0�1Interbase
�0�1Informix
�0�1mSQL
�0�1MS SQL Server
�0�1MySQL
�0�1Oracle
�0�1ODBC
�0�1PostgreSQL
�0�1SQLite
�0�1Sybase
PEAR:DB的下载地址:http://pear.php.net/package/DB/download。
17.2.2 ADODB
ADODB(Active Data Objects DataBase),起源于2000年,到目前为止仍然在增强与更新,发展至今仍然是一个热门的数据抽象层。
ADODB的开发初衷,源于很多从Microsoft ASP或ADO转过来的工程师,很多用法与MS ADO非常相像,目前使用ADODB的流行软件,例如egroupware、Mambo等均采用ADODB。
ADODB的数据库封包程序库提供了共通的应用程序界面来跟所有支持的数据库沟通,值得一提的是,它除了支持PHP,还支持Python语言。
ADODB提供很多实用的方法,使它超越了一个抽象层的功能,如具有表格化和数据库缓存等非常好的特性。ADODB支持的数据库系统包括:
�0�1Access
�0�1ADO
�0�1DB2
�0�1Firebird
�0�1FoxPro
�0�1FrontBase
�0�1Informix
�0�1Interbase
�0�1LDAP
�0�1MS SQL Server
�0�1MySQL
�0�1ODBC
�0�1Oracle
�0�1PostgreSQL
�0�1SAP DB
�0�1SQLite
�0�1Sybase
另外,因为ADODB的逐渐发展,特性增强,使得本身体积过大,为此ADODB开发团队还提供了基本功能的ADO Lite。
有关ADODB的使用和开发方法,我们会在17.4节重点介绍。
17.2.3
Metabase
Metabase由Manuel Lemons开发。Metabase已被誉为慢抽象层,但是它支持PHP的全部版本,也是目前提供最大的可移植性设计的唯一抽象层。目前支持的数据库系统包括:
�0�1Access
�0�1Informix
�0�1Interbase
�0�1mSQL
�0�1MS SQL Server
�0�1MySQL
�0�1ODBC
�0�1Oracle
�0�1PostgreSQL
�0�1SQLite
下载地址:http://www.phpclasses.org/browse/package/20.html#download。
17.2.4 MDB
SCMV-MDB的性能介于和融合PEAR:DB、Metabase数据库抽象层之间,它的初衷就是试图改善性能和最大可移植性。稳定版于2004年4月发布。
MDB目前支持的数据库系统包括:
�0�1Firebird
�0�1Frontbase
�0�1Interbase
�0�1MS SQL Server
�0�1MySQL
�0�1Oracle
�0�1PostgreSQL
�0�1Querysim
PEAR:MDB下载地址:http://pear.php.net/package/MDB/download。
17.2.5 MDB2
PEAR:MDB2把Metabase/PEAR:DB合并,并在SCMV-MDB的基础上进一步巩固,以及去除不必要的冗余工作。另外,它还整合了与PDO的接口。
PEAR:MDB2目前支持的数据库系统包括:
�0�1Firebird
�0�1Frontbase
�0�1Interbase
�0�1MS SQL Server
�0�1MySQL
�0�1Oracle
�0�1PostgreSQL
�0�1Querysim
�0�1SQLite
PEAR:MDB2下载地址:http://pear.php.net/package/MDB/download。
17.2.6 Creole
Creole是基于Java的JDBC技术,在某种程度上是PEAR:DB、PEAR: MDB2和ADODB的结合体。
Creole是PHP 5上较新的数据抽象层,与PHP 4不兼容。Creole提供充分的面向对象开发的API,以及PHP 5的异常处理机制。
Creole目前支持的数据库系统包括:
�0�1MySQL
�0�1MS SQL Server
�0�1Oracle(in progress)
�0�1PostgreSQL
�0�1SQLite
Creole库的下载地址:http://creole.phpdb.org/wiki/index.php?node=2。
17.2.7 PDO
PDO数据抽象层是随着PHP 5.1推出的,PDO使用C语言编写,因为是与PHP同级的API,所以它的执行速度快。PDO目前支持的数据库系统包括:
�0�1Firebird
�0�1FreeTDS
�0�1Interbase
�0�1MySQL
�0�1MS SQL Server
�0�1ODBC
�0�1Oracle
�0�1PostgreSQL
�0�1SQLite
�0�1Sybase
PDO必须运行在PHP 5.1及以上版本上。本章会重点讲述PDO的编写方法。
17.2.8 PHPLib
到目前为止,PHPLib已经使用了近6年,只是因为它曾经是非常受欢迎的数据库类,它在设计时并不是一个数据库抽象层,而只用于概括连接串、查询和处理错误和封装。
因为它小巧方便,加载速度快,现在使用这个类作为数据库层查询的PHP项目也为数不少。PHPLib的官方网站为:http://phplib.sf.net。技术不分高低,只分了解先后!PHPChina是个互助友爱的大家庭,谁都可以参与!  
UID1 帖子2925 精华7 积分9643 阅读权限200 在线时间2492 小时 注册时间2005-8-17 最后登录2007-11-4 查看详细资料
编辑用户
禁止用户
引用 使用道具 报告 回复 TOP
10月份Blog之星:Web江湖
phpchina
管理员
个人空间 发短消息 加为好友 当前离线  2# 大 中 小 发表于 2007-11-1 18:55  只看该作者
17.3PDO数据库抽象类
17.3.1 PDO简介
PDO(PHP Data Objects Layer)提供一个公共的数据库系统接口,它使用C语言做底层开发,运行速度比较快。
PDO以PHP 5.1为基础进行设计,设计沿承PHP的特点,以简洁易用为准,从严格意义上讲,PDO应该归为PHP 5的SPL库之一,而不应该归于数据抽象层,因为其本身和MySQL和MySQLi扩展库的功能类似。
17.3.2 PDO的安装
PDO本身结果是模块化的,它被分成一个公共核心,以及一个或多个驱动程序扩展,公共核心提供了在脚本(PDO本身)中使用的API,驱动程序扩展则为PDO和本地RDBMS客户机API库架起一座桥梁,用来访问指定的数据库系统。比如,IBM DB2用户会希望使用PDO_ODBC驱动程序,Oracle用户会用Oci8_PDO接口,MySQL用户则会用pdo_mysql驱动程序。
PDD的核心在PHP 5.2下默认为开启状态,驱动程序除pdo_sqlite之外,都需要手工打开。
下面是在FreeBSD环境下使用Ports安装PDO核心驱动程序的步骤:
cd /ports/database/pecl-PDO
make install
安装后,它会自动修改php.ini配置文件,如果没有该项则自行加入:
extension=pdo.so
安装PDO MySQL驱动程序:
cd /ports/database/pecl-PDO_MYSQL/
make install
修改php.ini文件,在刚才的项后加入该段:
extension=pdo_mysql.so
使用apachectl –k restart命令重新启动Apache后,即可完成PDO的安装了。
在Win32环境中,由于PHP 5.1版本以上的压缩包里已经自带PDO扩展库文件,因此只要在php.ini文件中打开该扩展即可,不需要再安装。
17.3.3 PDO连接数据库
其实,PDO与其他数据库接口和数据库抽象层使用区别不大,首先创建一个连接句柄:
复制PHP内容到剪贴板PHP代码:
   // 连接MySQL数据库的账号
   $login = "root";
   $passwd = "root";
   $db = new PDO('mysql:host=localhost;dbname=test',$login, $passwd);
   //如果连接失败,则抛出异常
   try {
      foreach($db->query('select * from test') as $row){ //查询数据库
      print_r($row);
   }
   $db=null;//关闭数据库连接
   } catch (PDOException $e) {
      echo $e->getMessage();
   }
?>
(1)使用持久连接pconnect
持久连接的好处是能够避免在每个页面命中时都打开和关闭数据库服务器连接,速度更快,如Oracle数据库的一个进程创建了两个连接,PHP则会把原有连接与新的连接合并共享为一个连接。pdo_connect.php脚本如下:
复制PHP内容到剪贴板PHP代码:
   //连接MySQL数据库的账号
   $login = "root";
   $passwd = "root";
   $opt = array(PDO::ATTR_PERSISTENT => TRUE);
   try {
      $db = new PDO('mysql:host=localhost;dbname=test,$login,$passwd,$opt);
   } catch (PDOException $e) {
      echo $e->getMessage();
   }
?>
(2)使用DSN- ODBC方式连接数据库
一个DSN(数据源名称)是一个标识符,定义为一个ODBC的数据源驱动。格式为:
Database name数据库名称
Directory目录
Database driver数据库驱动
User ID登录
Password密码
在UNIX系统下,DSN的配置通常存储在ini文件中,使用PDO读取文件配置,代码如下:
复制PHP内容到剪贴板PHP代码:
   ini_set(“pdo.dsn.dbserver”, “mysql::test”);
   try {
      $db = new PDO(“dbserver”);
   } catch (PDOException $e) {
      echo $e->getMessage();
   }
?>
17.3.4  使用PDO查询
使用PDO进行查询执行,可以使用两种方法。
第一种方法是预处理句柄(Prepared Statements),推荐使用,速度快而且安全。请看下例:
复制PHP内容到剪贴板PHP代码:
   require_once('pdo_connect.php');
   $rs = $db->prepare("SELECT * FROM test");
   $rs->execute();
   while($row = $rs->fetch()){
     print_r($row);
   }
?>
Prepared预处理语句的作用是,编译一次,可以多次执行,可以有效防止SQL注入,在执行单个查询时快于直接使用query()/exec()的方法。
1.绑定参数使用Prepared预处理语句做INSERT操作时的参数需要赋一个名字,以及绑定一个变量。
复制PHP内容到剪贴板PHP代码:
: #007700">= $db->prepare(“INSERT INTO users VALUES(:name,:pass,:mail)”);
foreach (array(‘name’,’pass’,’mail’) as $v){
   $stmt->bindParam(‘:’.$v,$$v); }
   $fp = fopen(“./users.csv”, “r”);
   while (list($name,$pass,$mail) = fgetcsv($fp,4096)){
      $stmt->execute();
   }
}
2.绑定结果列结果列可以绑定为变量,请看下面例子。
复制PHP内容到剪贴板PHP代码:
#007700">= “SELECT :type, :data FROM images LIMIT 1”;
   $stmt = $db->prepare($qry);
   $fp = fopen(tempname(“/tmp”, “LOB”), “w”);
   $stmt->bindColumn(‘:type’,$type);
   $stmt->bindColumn(‘:type’,$fp, PDO::PARAM_LOB);
   $stmt->execute(PDO::FETCH_BOUND);
   header(“Content-Type: “.$type);
   fflush($fp);
   fseek($fp, 0, SEEK_SET);
   fpassthru($fp);
   fclose($fp);
第二种方法就是直接执行。
直接执行常见于直接查询操作或更新数据库操作,可以使用exec()方法,请看下面的例子。
$db = new PDO(“DSN”);
$db->exec(“INSERT INTO foo (id) VALUES(‘bar’)”);
$db->exec(“UPDATE foo SET id=‘bar’”);
该方法返回的是操作影响的行数,若执行错误,则返回False值。
在一些UPDATE的查询执行后,若没有影响到列,则返回0值,我们可以根据它返回的值或布尔值来进行相关处理。例如:
$qry = “UPDATE foo SET id=‘bar’”;
$res = $db->exec($qry) or die(); //错误的返回
if (!$res) //未执行成功
if ($res !== FALSE) // 执行正确并返回
一个完整的例子:
复制PHP内容到剪贴板PHP代码:
   $dsn = "mysql:host=localhost;dbname=test";
   $db = new PDO($dsn, 'root', '');
   //如果为持续性连接,则修改为下面样式
   //$db = new PDO($dsn, 'root', '', array(PDO::ATTR_PERSISTENT => true));
   $count = $db->exec("INSERT INTO foo SET id = NULL,name = 'john',gender='male',time=NOW()");
   echo $count;
   $db = null;
?>
17.3.5 错误与异常处理
PDO提供两个方法来取得错误信息:
�0�1errorCode()——SQL语句错误,如:42000 == 语法错误;
�0�1errorInfo()——更详细的错误信息。
如下所示为错误信息内容:
array(
[0] => 42000,
[1] => 1064
[2] => Syntax Error
)
1.面向过程的处理
复制PHP内容到剪贴板PHP代码:
  $db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
  $rs = $db->query("SELECT aa,bb,cc FROM foo");
  if ($db->errorCode() != '00000'){
    print_r($db->errorInfo());
    exit;
  }
  $arr = $rs->fetchAll();
  print_r($arr);
  $db = null;
?>
PDO和PDOStatement对象有errorCode()和errorInfo()方法,如果没有任何错误,errorCode()返回的是00000;否则,就会返回一些错误代码。errorInfo()返回的是一个数组,包括PHP定义的错误代码和MySQL的错误代码及错误信息。数组结构如下:
Array
(
 [0] => 42S22
 [1] => 1054
 [2] => Unknown column 'aaa' in 'field list'
)
每次执行查询以后,errorCode()的结果都是最新的,所以我们可以很容易地自己控制错误信息显示。
2.面向对象的处理标准的错误句柄,应该是一个面向对象方法来扩展PDO,以允许错误句柄取得系统异常。
请看下面的例子,如果查询出错,将抛出异常。
$db->setAttribute(
   PDO::ATTR_ERRMODE,
   PDO::ERRMODE_EXCEPTION
);
一个完整的例子:
复制PHP内容到剪贴板PHP代码:
  try {
   $db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
   $db = null;
  } catch (PDOException $e) {
   print "Error: " . $e->getMessage() . "
";
   die();
  }
?>
使用PHP 5的异常处理:这里利用PHP 5面向对象的异常处理特征,如果里面有异常,就调用PDOException来初始化一个异常类。
PDOException异常类的属性结构如下:
复制PHP内容到剪贴板PHP代码:
   class PDOException extends Exception{
   //错误信息,可以调用 PDO::errorInfo() 或 PDOStatement::errorInfo()来访问
   public $errorInfo = null;
   //异常信息,可以使用 Exception::getMessage() 来访问
   protected $message;
   //SQL状态错误代码,可以使用 Exception::getCode() 来访问
   protected $code;
}
?>
这个异常处理类使用了PHP 5的异常处理类,下面简单地看一下PHP 5内置的异常处理类结构。
复制PHP内容到剪贴板PHP代码:
   class Exception{
      //属性
      protected $message = 'Unknown exception'; //异常信息
      protected $code = 0; //用户自定义异常代码
      protected $file; //发生异常的文件名
      protected $line; //发生异常的代码行号
      //方法
      final function getMessage(); //返回异常信息
      final function getCode(); //返回异常代码
      final function getFile(); //返回发生异常的文件名
      final function getLine(); //返回发生异常的代码行号
      final function getTrace(); //backtrace()数组
      final function getTraceAsString(); //已格式化成字符串的 getTrace() 信息
   }
?>
相应的,在代码中可以合适地调用getFile()和getLine()来进行错误定位,以更方便地进行调试。
17.3.6取得查询结果
PDO最大的特点之一是它的灵活性,本节将介绍如何取得查询结果,包括:
�0�1数组(数值或关联数组);
�0�1字符串(单列的结果集);
�0�1对象;
�0�1回调函数。
1.快取一行FetchColumn是为应用程序取得一个仅包含单列的数据,代码如下:
复制PHP内容到剪贴板PHP代码:
   $u = $db->query(“SELECT id FROM users WHERE login=‘login’ AND password=‘password’”);
   fetch(PDO::FETCH_COLUMN)
   if ($u->fetchColumn()) { //返回一个字符串
      //登录成功
   } else {
      //验证失败
}
?>
2.取得一个标准对象还可以将取得的一行作为一个标准类stdClass的对象实例,其中列名=属性名。
复制PHP内容到剪贴板PHP代码:
   $res = $db->query(“SELECT * FROM foo”);
   while ($obj = $res->fetch(PDO::FETCH_OBJ)) {
     // $obj == instance of stdClass
   }
?>
3.存取为一个类 PDO允许将结果保存为一个类,例子如下:
复制PHP内容到剪贴板PHP代码:
   $res = $db->query(“SELECT * FROM foo”);
   $res->setFetchMode(
      PDO::FETCH_CLASS,
      “className”,
      array(‘optional’=‘Constructor Params’)
   );
   while ($obj = $res->fetch()) {
      // $obj == instance of className
   }
?>
4.从一个类取得常量PDO允许查询的结果可以被用来生成一个目的类。
复制PHP内容到剪贴板PHP代码:
   $res = $db->query(“SELECT * FROM foo”);
   $res->setFetchMode(
      PDO::FETCH_CLASS |
      PDO::FETCH_CLASSTYPE
   );
   while ($obj = $res->fetch()) {
      // $obj == instance of class who’s name is
      // found in the value of the 1st column
   }
?>
5.存取为一个对象PDO还允许获取数据到一个已经存在的对象。
复制PHP内容到剪贴板PHP代码:
   $u = new userObject;
   $res = $db->query(“SELECT * FROM users”);
   $res->setFetchMode(PDO::FETCH_INTO, $u);
   while ($res->fetch()) {
      // 取得的记录集将放在$u这个对象变量中,在此显示
   }
?>
6.存取为关联数据PDO实现了迭代器(Iteator)接口,允许一个方法实现迭代的功能。
复制PHP内容到剪贴板PHP代码:
   $res = $db->query(
   “SELECT * FROM users”,PDO::FETCH_ASSOC);
   foreach ($res as $row) {
     // $row是一个关联数组,可以直接显示,如$row['id']
   }
?>
7.fetchAll()方法PDO也提供了和ADODB类似的fetchAll()方法,它允许从一个结果集中取得数据,然后放于关联数组中。
复制PHP内容到剪贴板PHP代码:
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
$qry = “SELECT * FROM users”;
$res = $db->query($qry)->fetchAll(PDO::FETCH_ASSOC);
?>
或者获取到索引数组里:
复制PHP内容到剪贴板PHP代码:
$res = $db->query("SELECT * FROM foo");
$result_arr = $res->fetchAll();
print_r($result_arr);
?>
数字索引数组比较浪费资源,请尽量使用关联数组,这样可以在内存中使用相当密集的大型结果集。
相关说明如下:
setAttribute()方法用于设置部分属性,主要属性有:PDO::ATTR_CASE、PDO::ATTR_ERRMODE等,这里需要设置的是PDO::ATTR_CASE,就是使用关联索引获取数据集时,关联索引是大写还是小写,有如下几个选择:
�0�1PDO::CASE_LOWER——强制列名是小写;
�0�1PDO::CASE_NATURAL——列名按照原始的方式;
�0�1PDO::CASE_UPPER——强制列名为大写。
我们使用setFetchMode方法来设置获取结果集的返回值的数据类型,类型有:
�0�1PDO::FETCH_ASSOC——关联数组形式;
�0�1PDO::FETCH_NUM——数字索引数组形式;
�0�1PDO::FETCH_BOTH——两种数组形式都有,这是默认的;
�0�1PDO::FETCH_OBJ——按照对象的形式,类似于以前的 mysql_fetch_object()。
当然,一般情况下,我们使用PDO::FETCH_ASSOC取得关联数组。具体使用哪种类型,应按照自己的实际应用选择。
8.fetchColumn()方法如果想获取指定记录里的一个字段结果,则可以使用PDOStatement::fetchColumn()。
复制PHP内容到剪贴板PHP代码:
   $rs = $db->query("SELECT COUNT(*) FROM foo");
   $col = $rs->fetchColumn();
   echo $col;
?>
一般使用fetchColumn()方法进行count统计,对某些只需要单字段的记录可以很好地操作。
9.回调函数PDO还规定在每一个fetch模式下,经过处理后的结果中使用一个回调函数。
复制PHP内容到剪贴板PHP代码:
function draw_message($subject,$email) { … }
$res = $db->query(“SELECT * FROM msg”);
$res->fetchAll(PDO::FETCH_FUNC,“draw_message”);
?>
10.直接查询的问题直接使用Query查询行每次都会直接提交给数据库,如果查询较多,每次频频查询将导致效率降低。
另外,在安全问题上,没有过滤一些特殊字符容易产生SQL注入。
11.过滤字符下面我们来看看如何使用PDO进行过滤引起SQL注入的方法,即过滤特殊字符。我们在PDO中使用quote()方法,使用例子如下:
   $query = “SELECT * FROM users WHERE
   login=“.$db->quote($_POST[‘login’]).”
   AND
   passwd=“.$db->quote($_POST[‘pass’]);
12.事务处理PDO驱动程序支持所有的事务数据库,并且PDO提供更简便的方法,如下:
复制PHP内容到剪贴板PHP代码:
   $db->beginTransaction();
   if ($db->exec($qry) === FALSE) {
      $db->rollback();
   }
   $db->commit();
?>
13.执行一个批处理事务在下面的示例中,假设我们为一个新雇员创建一组条目,这个雇员有一个ID号,即23。除了输入这个雇员的基本数据外,还需要记录雇员的薪水。分别完成两个更新很简单,但通过将这两个更新包括在beginTransaction()和commit()调用中,就可以保证在更改完成之前,其他人无法看到更改。如果发生了错误,catch块可以回滚事务开始以来发生的所有更改,并打印出一条错误消息。代码内容如下:
复制PHP内容到剪贴板PHP代码:
   try {
      $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
      array(PDO_ATTR_PERSISTENT => true));
      echo "Connected\n";
      $dbh->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
      $dbh->beginTransaction();
      $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
      $dbh->exec("insert into salarychange (id, amount, changedate)
      values (23, 50000, NOW())");
      $dbh->commit();
   } catch (Exception $e) {
      $dbh->rollBack();
      echo "Failed: " . $e->getMessage();
   }
?>
并不是一定要在事务中做出更新,也可以通过复杂的查询来提取数据,还可以使用信息构建更多的更新和查询。当事务在活动时,可以保证其他人在工作进行当中无法做出更改。事实上,这不是100%的正确,但如果您之前没有听说过事务的话,这样介绍也未尝不可。
下面是一个扩展PDO&PDO语句的类,内容如下:
复制PHP内容到剪贴板PHP代码:
   class Database extends PDO{
      function __construct()
      {
         parent::__construct('mysql:dbname=test;host=localhost', 'root', '');
         $this->setAttribute(PDO::ATTR_STATEMENT_CLASS,array('DBStatement'array($this)));
      }
   }
   class DBStatement extends PDOStatement{
      public $dbh;
      protected function __construct($dbh)
      {
         $this->dbh = $dbh;
         $this->setFetchMode(PDO::FETCH_OBJ);
      }
      public function foundRows()
      {
         $rows = $this->dbh->prepare('SELECT found_rows() AS rows',array(PDO::MYSQL_ATTR_ USE_BUFFERED_QUERY => TRUE));
         $rows->execute();
         $rowsCount = $rows->fetch(PDO::FETCH_OBJ)->rows;
         $rows->closeCursor();
         return $rowsCount;
      }
}
?>
14.存储过程在MySQL一章,我们已经了解了存储过程的创建,下面我们来看使用PDO调用的例子:
复制PHP内容到剪贴板PHP代码:
   $stmt = $dbh->prepare("CALL sp_set_string(?)");
   $stmt->bindParam(1, $str);
   $str = ‘hospinfo’; //绑定参数
   $stmt->execute();
?>
与先前讲过的绑定例子差不多,只是这里使用了“?”数据绑定方法,sp_set_string是存储过程名称。
带有输出参数的存储过程:
复制PHP内容到剪贴板PHP代码:
   $stmt = $dbh->prepare("CALL sp_get_string(?)");
   $stmt->bindParam(1, $ret,PDO:ARAM_STR, 4000);
   if ($stmt->execute()) {
      echo "返回值 $ret\n";
   }
   下面是绑定列输出的脚本例子:
   $stmt = $dbh->prepare("SELECT extension, name from CREDITS");
   if ($stmt->execute()) {
      $stmt->bindColumn('extension', $extension);
      $stmt->bindColumn('name', $name);
      while ($stmt->fetch(PDO::FETCH_BOUND)) {
         echo "Extension: $extension\n";
         echo "Author: $name\n";
      }
   }
?>技术不分高低,只分了解先后!PHPChina是个互助友爱的大家庭,谁都可以参与!  
UID1 帖子2925 精华7 积分9643 阅读权限200 在线时间2492 小时 注册时间2005-8-17 最后登录2007-11-4 查看详细资料
编辑用户
禁止用户
引用 使用道具 报告 回复 TOP
10月份Blog之星:L*A*M*P---我的选择,我的路!
dx_andy
PHPLamp站长
见习版主
个人空间 发短消息 加为好友 当前离线  3# 大 中 小 发表于 2007-11-1 21:07  只看该作者
刚才看了几章写的不错,明天到地下书城看一下能不能买到.
只买过一本59的PHP书
79*8=63 如果买的话这是我买的最贵的PHP书了.
不过还是支持!!!  PHPLamp站第三版(仿Discuz页面风格)上传成功,测试中……
网址:phplamp.com   phplamp.cn  
UID41037 帖子236 精华0 积分502 阅读权限100 来自河北省保定市 在线时间112 小时 注册时间2007-8-25 最后登录2007-11-4 查看个人网站
查看详细资料
编辑用户
禁止用户
引用 使用道具 报告 回复 TOP
10月份Blog之星:Web江湖
phpchina
管理员
个人空间 发短消息 加为好友 当前离线  4# 大 中 小 发表于 2007-11-1 21:59  只看该作者
17.4 ADODB
PHP在数据库的支持上是很令人称道的,几乎所有的知名数据库系统都有对应的函数库支持,而且支持得很完整。但遗憾的是,每一群数据库支持函数无论在名称或参数结构上,都有很大的差异,这使得PHP的系统开发者在面临更换数据库时,总会觉得痛苦万分。
难道这个问题就没有解决方法吗?当然有,答案就是将要介绍的ADODB这个PHP类库。
ADODB提供了完整的方法和属性,可以用来控制数据库系统,更棒的是你只要记得它的功能即可,因为不同的数据库系统,只要修改一个属性值,ADODB就会自动依据设定取用正确的PHP函数。
此外,再配合数据库系统修改SQL命令,这样PHP系统就可以在最短的时间内更换到另一个数据库系统;如果在编写程序时,对SQL命令能做妥善规划,那就更快了。
经过以上的介绍,相信你已经对ADODB的功用有所了解了,以下为ADODB的详细介绍。
下载ADODB:可以在http://adodb.sourceforge.net/ 取得最新版的ADODB(见图17-2)。
   2.JPG (105.84 KB)
2007-11-1 22:03
图17-2
ADODB的最新版本是adodb495a版,根据需要,可以下载完整版本的ADODB。如果您主要使用MySQL,则可以下载ADODB的lite版本,减少体积和一些不必要的系统开销。
17.4.1 使用ADODB
由于PHP的数据库存取函数没有标准化,所以需要一组函数库或类别来隐藏不同数据库函数界面间的差异。可以实现相对简单的数据库系统移植,这就是ADODB抽象层要实现的目标。
ADODB目前支持的数据库系统MySQL、Oracle、MS SQL Server、Sybase/Sybase SQL Anywhere、Informix、PostgreSQL、FrontBase、Interbase(Firebird及Borland版本)、Foxpro、Access、ADO和ODBC连接。
与其他数据库抽象层相比,其他类大多集中在处理与SELECT操作有关的内容,而ADODB对于INSERT及UPDATE操作也提供额外的支持,并且可以很快连接到多类数据库,提供的统计方法,在底层实现字串连接及字串标记变量的差异处理(在某些数据库中,字串的连接和标记符号是有差异的)。
字段类型对照系统是ADODB抽象层的特性之一,所以我们可以描述像CHAR、TEXT(而Oracle是Clob类型)及STRING这样的通用字段类型,而不必理会采用的数据库使用的是哪种类型,它会在底层替我们做对应和转换。
因此使用ADODB开发,对于系统来说移植相对变得容易,因为所有与数据库相依存的程序代码被都隐藏在后端,使用者不再需要去移植类别里的逻辑。
ADODB拥趸者很多,很多著名的开源软件:PostNuke、phpWiki、Mambo、eGroupware等,都使用ADODB作为数据库抽象类库。
17.4.2 ADODB安装
首先要将全部文件解压缩到Web服务器目录里,如lib/adodb。要测试ADODB则需要一个数据库,打开testdatabase.inc.php 这个文件,并且修改连接参数,以适合你所使用的数据库。这个程序会在你的数据库中建立一个新的资料表,以支持我们提供的测试程序及范例。
17.4.3  启动ADODB
当要执行ADODB时,至少有两个文件要被加载进来,第一个是 ADOdb.inc.php,这里面包含了所有数据库类中要被使用的函数。而对数据库操作的程序代码则被放置在ADOdb.inc.php文件里。
ADODB可以连接的名称及对应的数据库系统,如表17-1所示。
表17-1
   3.JPG (14.38 KB)
2007-11-1 22:14
下面我们来看怎么使用ADODB连接数据库。
1.连接MySQL数据库我们使用如下方法连接一个MySQL数据库:
require_coce('/libs/adodb/ADOdb.inc.php');
$conn = &ADONewConnection('mysql');
无论连接到一个什么类型的数据库,我们都要使用ADONewConnection()函数来创建一个连接对象。
ADONewConnection接收一个选择性参数:,用以表示要连接的数据库。如果没有参数被指定,它将会使用ADOLoadCode() 内部方法所载入的最后一个数据库。
当建立好一个连接对象后,我们还没有真正连接上数据库,需要使用$conn->Connect()或者$conn->PConnect() 两个方法,任选其一来完成真正的数据库连接:
$conn -> Connect(DB_HOST,DB_USER,DB_PASSWORD,$database)
下面是创建一个mysql数据库连接对象,并创建一个数据库连接:
复制PHP内容到剪贴板PHP代码:
: #007700">= ADONewConnection('mysql'); //创建一个ADODB连接对象
$mysql_obj = $conn->connect('localhost','root','passwd','dbname'); //连接到MySQL服务器
if (!$ora_obj) {
   echo $mysql_conn->ErrorMsg(); //显示连接的错误信息
   exit();
}else{
   $mysql_conn -> SetFetchMode(3);
}
Var_dump($mysql_obj);
这样我们就创建好与本地MySQL服务器的连接了。可以看到,ADODB连接数据库同样很方便。
2.连接Oracle数据库
如果要连接Oracle数据库该如何写呢?结合表17-1,我们可以编写脚本如下:
复制PHP内容到剪贴板PHP代码:
require_once ("libs/adodb/adodb.inc.php");
$ora_conn = &ADONewConnection('oci8');
$ora_obj = $ora_conn -> Connect('localhost','oracle','oracle','oradb');
if (!$ora_obj) {
   echo $ora_conn->ErrorMsg();
   exit();
}else{
   $ora_conn -> SetFetchMode(3);
}
Var_dump($ora_conn);
注意:连接Oracle数据库需要在PHP本地环境安装好Oracle的客户端驱动,以及连接文件设置。
其中,SetFetchMode(3)指的是取得记录集时,返回的是二维关联数组。也可以使用字符形式,这样更明了一些:
$mysql_conn->SetFetchMode(ADODB_FETCH_ASSOC);
17.4.4  ADODB的查询方法
ADODB的查询方法如下。
1.直接查询
Excute()方法通过连接句柄执行SQL查询,并返回一个变量,如下:
$sql='SELECT * FROM ice_cream WHERE flavor LIKE ?';
$res = $cnx->Execute($sql,array('Chocolate'));
2.缓存查询
ADODB提供内置的缓存机制,CacheExecute()方法用于每次查询数据时,会把相应的结果序列化后保存到文件中,以后同样的查询语句就可以不用直接查询数据库,而是从缓存文件中获取,从而提高Web系统的性能。CacheExecute()方法的格式如下:
CacheExecute($ttc,$sql)
该方法以缓存的形式执行一段查询,其中$ttc为缓存的时间,请看如下代码:
$ADODB_CACHE_DIR = "/var/tmp/adodb_cache"; //缓存保存的文件目录
$sql = "SELECT surname, age FROM employees"; //构造一个查询
$rs = &$db->CacheExecute(600,$sql);
// 缓存式查询,缓存将被保存600秒后更新
3.清除缓存CacheFlush()
该方法用来清除所有ADODB数据库的缓存。  
17.4.5 移动记录集
记录集(Record Set):从执行的方法中返回指定的记录,使用moveFirst()、moveLast()、moveNext()和move($n)方法访问记录集中的一个指定记录。例如:
复制PHP内容到剪贴板PHP代码:
0">=$cnx->Execute('SELECT flavor,price FROM ice_cream');
$rs->MoveLast();
print "Flavor ".$rs->fields[0]." costs "
.$rs->fields[2]."\n";
$rs->MoveFirst();
//省略...
$rs->Move(2);
//省略...
$rs->MoveNext();
设置一个全局变量$ADODB_FETCH_MODE,从ADODB_FETCH_NUM(或从ADODB_FETCH_ASSOC返回)中取得数字索引(或关联索引)数组。例如:
复制PHP内容到剪贴板PHP代码:
style="color: #007700">= ADODB_FETCH_ASSOC ;
$rs=$cnx->Execute('SELECT flavor,price FROM ice_cream');
print "\n";
while (! $rs->EOF) {
   print "".
   "n";
   $rs->MoveNext();
}
print "
".$rs->fields['flavor']}."  ".$rs->fields['price']"."
n";
FetchObject()方法也是一个记录集变量。
17.4.6 使用ADODB生成HTML
ADODB的rs2html($res)函数,它提供一个简单的方法,从$res变量中的记录自动生成HTML表格。
它在tohtml.inc.php中,使用时需要包含进来,如下代码:
require 'adodb/tohtml.inc.php';
//引入rs2html函数
require 'adodb/adodb.inc.php';
//省略...
$rs = $cnx->Execute('SELECT flavor,calories,price FROM ice_cream');
rs2html($rs);
使用rs2html($res,'CLASS="myClass")这种格式,表示指定表格使用的myClass的样式表类进行显示。
17.4.7 使用ADODB进行分页
ADODB_Pager(该方法定义在adodb-pager.inc.php中)提供一种简单分页显示记录的方法。
require 'adodb/adodb.inc.php';
require 'adodb/adodb-pager.inc.php';
$pager=new ADODB_Pager($cnx,"SELECT id,flavor,price FROM ice_cream_big");
$pager->Render();
使用$pager->Render($num)来设置每次显示的行数,默认值为10。
17.4.8  生成下拉选择菜单
getMenu($selectName)方法将帮助我们生成一个
可以看到,该列表菜单内容是从library表抽取的记录,列表框的名字为“library”,在记录集中,ID是菜单选项的值,名称为菜单框显示的元素。
由此可以看出,GetMenu()方法可以大幅度简化Web开发任务,大大减少代码量。
11.输出到文件ADODB还允许我们将记录输出为一个不同形式的文件:如逗号分隔符CSV文件,制表符表格,甚至于HTML形式的表格。
这些功能属于ADODB的附属功能,在使用时需要包含相关ADODB类文件,下面是样例的内容。
复制PHP内容到剪贴板PHP代码:
   include("libs/adodb/adodb.inc.php");
   // 包含转换方法的文件
   include_once("libs/adodb/toexport.inc.php");
   // 创建一个mysql连接实例对象
   $db = NewADOConnection("mysql");
   // 打开一个数据库连接
   $db->Connect("localhost", "root", "passwd", "library") or die("Unable to connect!");
   // 构造并执行一个查询
   $query = "SELECT title, id FROM library";
   $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg());
   // 返回一个CSV字符串
   echo rs2csv($result);
   // 关闭数据库的连接
   $db->Close();
?>
输出结果如下:
title,id
Mystic River,15
Where Eagles Dare,16
XML and PHP,17
我们也可以去除结果中第一行,即字段的名称,使用脚本格式如下:
// 返回一个 CSV 字符串
echo rs2csv($result, false);
脚本的输出结果将没有字段名称,如下:
Mystic River,15
Where Eagles Dare,16
XML and PHP,17
ADODB还提供生成制表符或分隔符文件功能,使用rs2tab()方法:
复制PHP内容到剪贴板PHP代码:
   include("libs/adodb/adodb.inc.php");
   // 包含转换方法的文件
   include("toexport.inc.php");
   //创建一个mysql连接实例对象
   $db = NewADOConnection("mysql");
   // 打开一个数据库连接
   $db->Connect("localhost", "root", "root", "library") or die("Unable to connect!");
   // 构造并执行一个查询
   $query = "SELECT title, id FROM library";
   $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg());
   // 返回一个TAB制表符分隔的字符串
   echo rs2tab($result);
   // 关闭数据库连接
   $db->Close();
?>
显示结果如下:
title   id
Mystic River   15
Where Eagles Dare   16
XML and PHP   17
ADODB还提供生成HTML表格的功能,使用rs2html()方法:
复制PHP内容到剪贴板PHP代码:
   include_once(“libs/adodb/adodb.inc.php”);
   // 包含转换方法的文件
   include_once("libs/adodb/tohtml.inc.php");
   // 创建一个mysql连接实例对象
   $db = NewADOConnection("mysql");
   // 打开一个数据库连接
   $db->Connect("localhost", "root", "passwd", "library") or die("Unable to connect!");
   // 构造并执行一个查询
   $query = "SELECT title, id FROM library";
   $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg());
   // 返回一个HTML格式的表格
   echo rs2html($result);
   // 关闭数据库连接
   $db->Close();
?>
输出结果如下:
   4.JPG (9.83 KB)
2007-11-1 22:14
技术不分高低,只分了解先后!PHPChina是个互助友爱的大家庭,谁都可以参与!  
UID1 帖子2925 精华7 积分9643 阅读权限200 在线时间2492 小时 注册时间2005-8-17 最后登录2007-11-4 查看详细资料
编辑用户
禁止用户
引用 使用道具 报告 回复 TOP
10月份Blog之星:L*A*M*P---我的选择,我的路!
phpchina
管理员
个人空间 发短消息 加为好友 当前离线  5# 大 中 小 发表于 2007-11-1 22:12  只看该作者
17.5 PHPLib
PHPLib可能是伴随PHP一同成长最老的数据库抽象层(但和ADODB相比,它只算是一个MySQL抽象类库),当前最新版本为7.4a。我们只需要它的数据库访问功能,除了支持MySQL外,它也同时支持访问Oracle 8以上版本的数据库。
PHPLib访问SQL数据的类名为DB_Sql,包含在db_mysql.inc.php文件中。我们要使用的仅是它的数据库抽象类,直接用require()和include()包含进来就可以进行开发了。下面是开发实例,并且所用类库都是最新版本,这些都可以在光盘中找到。
17.5.1 使用PHPLib查询
首先定义一个配置文件config.inc.php,用于扩展PHPLib的MySQL类:DB_Sql。代码内容如下:
复制PHP内容到剪贴板PHP代码:
/*** 系统路径,可根据需求更改路径 */
   define('ROOT', './');
/*** PHPLib library path */
   define('DB_HOST', 'localhost');
   define('DB_USER', 'root');
   define('DB_PASSWORD', 'root');
   define('DB_NAME', 'phpdev');
   require_once(ROOT."lib/db.inc.php");
   $db = new DbClass;
/*
    设置字符集,如utf-8和gbk、Latin1等,根据数据库的字符集而定,如果是Latin1,则可以不需要运行
*/
   $sql = "SET NAMES 'utf8'";
   $db->query($sql);
?>
上面代码引用的db.inc.php用于扩展DB_Sql类,主要是重新声明连接的数据库和账号,以及出错信息的处理和显示功能,如下所示。
复制PHP内容到剪贴板PHP代码:
   require_once("db_mysql.inc.php");
   class DbClass extends DB_Sql{
   public $Host;
   public $Database;
   public $User;
   public $Password;
   function __constructor()
   {
      $this->Host = DB_HOST;
      $this->Database = DB_NAME;
      $this->User = DB_USER;
      $this->Password = DB_PASSWORD;
   }
   function halt($msg)
   {
      printf("Database Error: %s
\n", $msg);
      printf("MySQL Error: %s (%s)
\n",
      $this->Errno, $this->Error);
      printf("Please contact administrator and report the ");
      printf("exact error message.
\n");
      die("Session halted.");
   }
}
?>
我们还以symbols表为例,查询该表的数据,然后全部显示出来。
复制PHP内容到剪贴板PHP代码:
   require_once('lib/config.inc.php');
   $sql = "SELECT * from symbols";
   //也可以使用该方法执行INSERT、UPDATE、DELETE等SQL查询
   $db->query($sql);
?>
   while($db->next_record()) {
      $country = $db->f("country");
      $animal = $db->f("animal");
      $cname = $db->f("cname");
      echo "";
      echo("\n");
      echo "";
   }
?>
国家:  $country  代表动物:  $animal ($cname)
显示结果如下:
   5.JPG (19.58 KB)
2007-11-1 22:23
关于$db->next_record(),这是一个没有返回值的语句,它的功能是将当前表的指针向前移动并更新Record、Error、Row、Errno的方法。
while($db->next_record()) {

}
我们根据它的指针循环操作,直至到达尾记录,若条件不满足,则while退出循环。
$name = $db->f("name");
给$name变量分配的是数据字段name的值。
echo("
国家: $country   代表动物: $animal ($cname)
\n");
echo("
\n\n");
打印出一行数据,也可不用变量赋值,而是直接引用方法返回的字段名即可,但是这种方法没有上面程序的可读性好。
复制PHP内容到剪贴板PHP代码:
while($db->next_record()) {
   echo("
国家: ".$db->f("country")."   代表动物: "
   .$db->f("animal")."(".$db-f("cname")."
\n");
   echo("
\n\n");
}
我们也可以开发一个函数,像ADODB或PDO那样,让抽出的记录生成一个二维关联数组。这样,PHPLib同样也可以与Smarty引擎协同工作,并且工作更方便,请看如下代码。
复制PHP内容到剪贴板PHP代码:
   function GetAll($sql){
      global $db;
      //全局PHPlib $db的实例
      $db->query($sql);
      $Array = array();
      $j= 0;
      while($db->next_record()) {
         $Array[$j]= $db->Record;
         $j++;
      }
      return $Array;
}
?>
然后把该方法放在一个文件中,比如func.inc.php,同样保存在lib目录下。这样,我们再不用每次都重复使用while循环,直接调用该函数即可。
复制PHP内容到剪贴板PHP代码:
   require_once('lib/config.inc.php');
   require_once('lib/func.inc.php');
   $sql = "SELECT * from symbols WHERE country='China'";
   $getAnimal = GetAll($sql);
   print_r($getAnimal);
?>
在浏览器上的显示结果如下:
Array
(
   [0] => Array
   (
      [0] => 2
      [id] => 2
      [1] => China
      [country] => China
      [2] => dragon
      [animal] => dragon
      [3] => 龙
      [cname] => 龙
   )
)
GetAll方法产生的$getAnimal关联数组和ADODB的是一样的,这样,我们可以让PHPLib和Smarty匹配,把该数组抛给模板显示即可。
虽然没有ADODB、PDO那么强大,但PHPLib小巧方便,对于系统负载相对较小。如果仍在旧版本下或虚拟主机环境下进行开发,使用它也是不错的选择。
17.6 小结
在本章中,我们一起了解了PDO及ADODB数据库类与抽象层在Web应用程序中的应用开发。其中包括记录集的概念(resultsets),如何连续获得表信息,如何使用PDO、ADODB进行优化查询,提高查询效率,以及结果缓存化的方法,如何输出HTML或其他格式文本的方法。
通过前面的介绍,相信您已经了解了数据库抽象层的特点和重要性:良好且丰富的功能和方法,方便使用,良好伸缩性与可移植性。
下一章,我们将要讨论PHP中热门且较实用的内容——页面模板化与Smarty技术。
特别参看:
http://www.docin.com/p-20938989.html

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/3042/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2011-9-2 17:11
评论列表
2010-7-16 14:06 | xyanyue
zan
分页: 1/1 第一页 1 最后页
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]