PHP 在5.1.和5.2.之间 PDO数据库有哪些操作中的不同

54872人阅读
作者:heiyeluren &&
关键字:PHP PHP5 PDO 数据库抽象类
(PHP Data Object) 是PHP 5新出来的东西,在PHP 6都要出来的时候,PHP 6只默认使用PDO来处理数据库,将把所有的数据库扩展移到了PECL,那么默认就是没有了我们喜爱的php_mysql.dll之类的了,那怎么办捏,我们只有与时俱进了,我就小试了一把PDO。(本文只是入门级的,高手可以略过,呵呵)
【PDO是啥】
PDO是PHP 5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,什么
、、、等等扩展来连接、PostgreSQL、、,同样的,我们必须借助 、、之类的数据库抽象类来帮助我们,无比烦琐和低效,毕竟,php代码的效率怎么能够我们直接用C/C++写的扩展斜率高捏?所以嘛,PDO的出现是必然的,大家要平静学习的心态去接受使用,也许你会发现能够减少你不少功夫哦。
【安装PDO】
我是在Windows XP SP2 上面,所以嘛,整个过程都是在Windows行进行的啦,至于Linux/FreeBSD等平台,请自行查找资料设置安装。
我的是PHP 5.1.4,已经自带有了php_pdo.dll的扩展,不过需要稍微设置一下才能使用。
,那是我的PHP配置文件,找到下面这行:
extension_dir
这个就是我们扩展存在的目录,我的PHP 5扩展是在:,那么我就把这行改成:
extension_dir = &C:/php5/ext&
然后再往php.ini下面找到:
;;;;;;;;;;;;;;;;;;;;;;
; Dynamic E
;;;;;;;;;;;;;;;;;;;;;;
下面有一堆类似 ;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,刚下载的,很爽,不怕流氓软件,哈哈。
在浏览器里面输入:,如果你的这个页面路径不一致,请自行输入。
输出的内容中,如果你能够顺利的看到:
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,但是我个人推荐大家使用 MySQL4.1.x 或者 MySQL 5.0.x,因为那些版本有很多有趣的东西值得去学习。我们这里PDO需要连接的就是我的MySQL4.0啦,如果你没有安装MySQL,请自行安装。我们建立好了MySQL,并且在test库里添加了表foo,包括id,name,gender,time等四个字段。
我们开始构造第一个PDO应用,建立一个pdo.php文件在Web文档目录下:
$dsn = &mysql:host=dbname=test&;
$db = new PDO($dsn, 'root', '');
$db-&exec(&INSERT INTO foo SET name ='heiyeluren',gender='男',time=NOW()&);
echo$count;
$db = null;
不明白啥意思,俺们来慢慢讲讲。这行:
$dsn = &mysql:host=dbname=test&;
就是构造我们的DSN(数据源),看看里面的信息包括:数据库类型是mysql,主机地址是localhost,数据库名称是test,就这么几个信息。不同数据库的数据源构造方式是不一样的。
$db = new PDO($dsn, 'root', '');
初始化一个PDO对象,构造函数的参数第一个就是我们的数据源,第二个是连接数据库服务器的用户,第三个参数是密码。我们不能保证连接成功,后面我们会讲到异常情况,这里我们姑且认为它是连接成功的。
$count = $db-&exec(&INSERT INTO fooSET name = 'heiyeluren',gender='男',time=NOW()&);
调用我们连接成功的PDO对象来执行一个查询,这个查询是一个插入一条记录的操作,使用PDO::exec()方法会返回一个影响记录的结果,所以我们输出这个结果。最后还是需要结束对象资源:
默认这个不是长连接,如果需要数据库长连接,需要最后加一个参数:变成这样:
$db = new PDO($dsn, 'root', '',array(PDO::ATTR_PERSISTENT =& true));
一次操作就这么简单,也许跟以前的没有太大区别,跟ADOdb倒是有几分相似。
【继续了解】
如果我们想提取数据的话,那么就应该使用数据获取功能。(下面用到的$db都是上面已经连接好的对象)
foreach($db-&query(&SELECT* FROM foo&)){
print_r($row);
我们也可以使用这种获取方式:
$rs = $db-&query(&SELECT* FROM foo&);
while($row =
$rs-&fetch()){
print_r($row);
如果想一次把数据都获取到数组里可以这样:
$rs = $db-&query(&SELECT* FROM foo&);
$result_arr =
$rs-&fetchAll();
print_r($result_arr);
[0] =& Array
[name] =& heiyeluren
[1] =& heiyeluren
[gender] =& 男
我们看里面的记录,数字索引和关联索引都有,浪费资源,我们只需要关联索引的:
$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,就是我们使用关联索引获取数据集的时候,关联索引是大写还是小写,有几个选择:
-- 强制列名是小写
-- 列名按照原始的方式
-- 强制列名为大写
我们使用setFetchMode方法来设置获取结果集的返回值的类型,同样类型还有:
PDO::FETCH_ASSOC-- 关联数组形式
PDO::FETCH_NUM -- 数字索引数组形式
PDO::FETCH_BOTH -- 两者数组形式都有,这是缺省的
PDO::FETCH_OBJ -- 按照对象的形式,类似于以前的mysql_fetch_object()
当然,一般情况下我们是使用PDO::FETCH_ASSOC,具体使用什么,按照你自己的需要,其他获取类型参考手册。
除了上面这种获取数据的方式,还有这种:
$rs = $db-&prepare(&SELECT* FROM foo&);
$rs-&execute();
while($row =
$rs-&fetch()){
print_r($row);
其实差不多啦。如果你想获取指定记录里一个字段结果的话,可以使用 PDOStatement::fetchColumn():
$rs = $db-&query(&SELECTCOUNT(*) FROM foo&);
$rs-&fetchColumn();
一般使用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. 面向对象的方式
先看看如果连接错误等的处理,使用面向对象的方式来处理:
$db = newPDO('mysql:host=dbname=test',
$db = null;
} catch (PDOException
print &Error: & .
$e-&getMessage() . &&br/&&;
这里利用我们PHP 5面向对象的异常处理特征,如果里面有异常的话就初始化调用PDOException来初始化一个异常类。
PDOException异常类的属性结构:
class PDOException
extendsException
public$errorInfo =
错误信息,可以调用 PDO::errorInfo()
或 PDOStatement::errorInfo()来访问
protected$message;
// 异常信息,可以试用Exception::getMessage()
protected$code;
// SQL状态错误代码,可以使用Exception::getCode()
这个异常处理类是集成PHP 5内置的异常处理类,我们简单的看一下PHP 5内置的异常处理类结构:
classException
protected$message = 'Unknownexception';
// 异常信息
protected$code = 0;
// 用户自定义异常代码
protected$file;
// 发生异常的文件名
protected$line;
// 发生异常的代码行号
finalfunction getMessage();
// 返回异常信息
finalfunction getCode();
// 返回异常代码
finalfunction getFile();
// 返回发生异常的文件名
finalfunction getLine();
// 返回发生异常的代码行号
finalfunction getTrace();
// backtrace() 数组
finalfunctiongetTraceAsString();
// 已格成化成字符串的 getTrace()
相应的,在代码中可以合适的调用
getFile() 和 getLine() 来进行错误定位,更方便的进行调试。
2. 使用面向过程的方法
先看代码:
$db = newPDO('mysql:host=dbname=test',
$rs = $db-&query(&SELECTaa,bb,cc FROM foo&);
if ($db-&errorCode() !='00000'){
print_r($db-&errorInfo());
$arr = $rs-&fetchAll();
print_r($arr);
$db = null;
PDO和PDOStatement对象有errorCode() 和
errorInfo() 方法,如果没有任何错误, errorCode() 返回的是:
<span style="color:#000,否则就会返回一些错误代码。errorInfo() 返回的一个数组,包括PHP定义的错误代码和MySQL的错误代码和错误信息,数组结构如下:
[0] =& 42S22
[1] =& 1054
[2] =& Unknown column 'aaa' in'field list'
每次执行查询以后,errorCode() 的结果都是最新的,所以我们可以很容易自己控制错误信息显示。
【简单总结】
从上面的使用看出,PDO功能确实强大,另外还有一些内容我没有讲到,比如绑定参数、预处理、存储过程、事务处理等等功能。另外还有不同数据扩 DSN的构造,Oracle数据库自己很多特殊的东西,都需要深入去学习理解,这篇文章就只是简单的描述了一些入门知识,算是对PDO一个简单的了解吧。
[ 参考资料 ]
PDO为何物?
POD(PHP Data Object)扩展在PHP5中加入,PHP6中将默认识用PDO连接,所有非PDO扩展将会在PHP6被从扩展中移除。该扩展提供PHP内置类 PDO来对数据库进行访问,不同数据库使用相同的名,解决数据库连接不统一的问题。
我是配置在windows下做开发用的。
■PDO的目标
提供一种轻型、清晰、方便的 API 统一各种不同 RDBMS 库的共有特性,但不排除更高级的特性。 通过 PHP 脚本提供可选的较大程度的抽象/兼容性。
■PDO的特点:
性能。PDO 从一开始就吸取了现有数据库扩展成功和失败的经验教训。因为 PDO 的是全新的,所以我们有机会重新开始设计性能,以利用 PHP 5的最新特性。 能力。PDO 旨在将常见的数据库功能作为基础提供,同时提供对于
RDBMS独特功能的方便访问。 简单。PDO 旨在使您能够轻松使用数据库。API 不会强行介入您的代码,同时会清楚地表明每个函数调用的过程。 运行时可扩展。PDO 扩展是模块化的,使您能够在运行时为您的数据库后端加载驱动程序,而不必重新编译或重新整个
PHP 程序。例如,PDO_OCI扩展会替代 PDO 扩展实现 数据库 API。还有一些用于
、PostgreSQL、ODBC 和Firebird 的驱动程序,更多的驱动程序尚在开发。
我这里是WINDOWS下开发用的PDO扩展,要是你要在下安装配置,请到别的地方寻找。
版本要求:
php5.1以及以后版本的程序包里已经带了;
php5.0.x则要到pecl.php.net下载,放到你的扩展库,就是PHP所在的文件夹的ext文件夹下;
手册上说5.0之前的版本不能运行PDO扩展。
修改你的php.ini配置文件,使它支持pdo.(php.ini这个东西没有弄懂的话,先弄清楚,要修改调用你的phpinfo()函数所显示的那个php.ini)
extension=php_pdo.dll前面的分号去掉,分毫是php配置文件注释符号,这个扩展是必须的。
;extension=php_pdo.dll
;extension=php_pdo_firebird.dll
;extension=php_pdo_informix.dll
;extension=php_pdo_mssql.dll
;extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_oci8.dll
;extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
;extension=php_pdo_sqlite.dll
各各扩展所对应的数据库是:
Driver nameSupported databasesPDO_DBLIBFreeTDS/ Microsoft SQL Server / SybasePDO_FIREBIRDFirebird/Interbase6PDO_INFORMIXInformix
Dynamic ServerPDO_MYSQLMySQL 3.x/4.xPDO_OCIOracle Call InterfacePDO_ODBCODBCv3 (IBM DB2, unixODBC and win32 ODBC)PDO_PGSQLPostgreSQLPDO_SQLITESQLite
3 and SQLite 2
你要使用哪种数据库,只要把相应的扩展前的注释符号&;&去掉就可以了。
我这里假设你已经装好mysql了,要是没装的话,麻烦先想办法装上,我的是mysql5.0.22,黑夜路人用的是MySQL4.0.26也可以用。
★数据库的连接:
我们通过下面的例子来分析PDO连接数据库,
$dbms='mysql';//数据库类型
Oracle 用ODI,对于开发者来说,使用不同的数据库,只要改这个,不用记住那么多的函数了
$host='localhost';//数据库主机名
$dbName='test';//使用的数据库
$user='root';//数据库连接用户名
$pass='';//对应的密码
$dsn=&$dbms:host=$dbname=$dbName&;
$dbh=newPDO($dsn,$user,$pass);//初始化一个PDO对象,就是创建了数据库连接对象$dbh
echo&连接成功&br/&&;
/*你还可以进行一次搜索操作
foreach($dbh-&query('SELECT
* from FOO')as$row){
print_r($row);//你可以用
echo($GLOBAL); 来看到这些&#20540;
$dbh=null;
}catch(PDOException$e){
die(&Error!: &.$e-&getMessage().&&br/&&);
//默认这个不是长连接,如果需要数据库长连接,需要最后加一个参数:array(PDO::ATTR_PERSISTENT =& true)
变成这样:
$db=newPDO($dsn,$user,$pass,array(PDO::ATTR_PERSISTENT=&true));
★数据库查询:
上面我们已经进行了一次查询,我们还可以使用如下的查询:
$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::setAttribute()的参数:
·&&&&&PDO::ATTR_CASE: 强制列名变成一种&#26684;式,详细如下(第二个参数):
·&PDO::CASE_LOWER: 强制列名是小写.
·&PDO::CASE_NATURAL: 列名按照原始的方式
·&PDO::CASE_UPPER: 强制列名为大写.
·&&&&&PDO::ATTR_ERRMODE: 错误提示.
·&PDO::ERRMODE_SILENT: 不显示错误信息,只显示错误码.
·&PDO::ERRMODE_WARNING: 显示警告错误.
·&PDO::ERRMODE_EXCEPTION: 抛出异常.
·&&&&&PDO::ATTR_ORACLE_NULLS(不仅仅是ORACLE有效,别的数据库也有效): )指定数据库返回的NULL&#20540;在php中对应的数&#20540;。
·&PDO::NULL_NATURAL: 不变.
·&PDO::NULL_EMPTY_STRING:Empty string is converted toNULL.
·&PDO::NULL_TO_STRING: NULLis converted to an empty string.
·&&&&&PDO::ATTR_STRINGIFY_FETCHES:Convert numeric values to strings when fetching. Requires bool.
·&&&&&PDO::ATTR_STATEMENT_CLASS: Setuser-supplied statement class derived from PDOStatement. Cannot be used withpersistent PDO instances. Requiresarray(stringclassname, array(mixed constructor_args)).
·&&&&&PDO::ATTR_AUTOCOMMIT(availablein OCI, Firebird and MySQL): Whether to autocommit every single statement.
·&&&&&PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(availablein MySQL): Use buffered queries.
例子中的$rs-&setFetchMode(PDO::FETCH_ASSOC);是PDOStatement::setFetchMode(),对返回类型的声明。
PDO::FETCH_ASSOC-- 关联数组形式
PDO::FETCH_NUM -- 数字索引数组形式
PDO::FETCH_BOTH -- 两者数组形式都有,这是缺省的
PDO::FETCH_OBJ -- 按照的形式,类&#20284;于以前的mysql_fetch_object()
更多返回类型声明(PDOStatement::方法名)看手册。
★插入,更新,删除数据,
$db-&exec(&DELETE FROM `xxxx_menu` where mid=43&);
简单的一下上面的操作:
查询操作主要是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 连接到了 mysql,在发出查询之前,您应该理解 PDO 是如何管理事务的。如果之前没有接触过事务,那么首先要知道事务的 4 个特征:原子性(Atomicity)、一致性(Consistency)、独立性(Isolation)和持久性(Durability),即 ACID。用外行人的话说,对于在一个事务中执行的任何,即使它是分阶段执行的,也一定可以保证该工作会安全地应用于数据库,并且在工作被提交时,不会受到来自其他连接的影响。事务性工作可以根据请求自动撤销(假设您还没有提交它),这使得脚本中的错误处理变得更加容易。
事务通常是通过把一批更改积蓄起来、使之同时生效而实现的。这样做的好处是可以大大提高这些更新的效率。换句话说,事务可以使脚本更快,而且可能更健壮(不过需要正确地使用事务才能获得这样的好处)。
不幸的是,并不是每种数据库都支持事务(Mysql5支持事务,mysql4我不知道),所以当第一次打开连接时,PDO 需要在所谓的“自动提交(auto-commit)”模式下运行。自动提交模式意味着,如果数据库支持事务,那么您所运行的每一个查询都有它自己的隐式事务,如果数据库不支持事务,每个查询就没有这样的事务。如果您需要一个事务,那么必须使用PDO::beginTransaction() 方法来启动一个事务。如果底层驱动程序不支持事务,那么将会抛出一个PDOException(无论错误处理设置是怎样的:这总是一个严重错误状态)。在一个事务中,可以使用PDO::commit()
或 PDO::rollBack() 来结束该事务,这取决于事务中运行的代码是否成功。
当脚本结束时,或者当一个连接即将被关闭时,如果有一个未完成的事务,那么 PDO 将自动回滚该事务。这是一种安全措施,有助于避免在脚本非正常结束时出现不一致的情况 —— 如果没有显式地提交事务,那么假设有某个地方会出现不一致,所以要执行回滚,以保证数据的安全性。
//例子来自http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0505furlong/index.html
$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();
在上面的示例中,假设我们为一个新雇员创建一组条目,这个雇员有一个 ID 号,即 23。除了输入这个人的基本数据外,我们还需要记录雇员的薪水。两个更新分别完成起来很简单,但通过将这两个更新包括在beginTransaction() 和 commit() 调用中,就可以保证在更改完成之前,其他人无法看到更改。如果发生了错误,catch 块可以回滚事务开始以来发生的所有更改,并打印出一条错误消息。
并不是一定要在事务中作出更新。您也可以发出复杂的查询来提取数据,还可以使用那种信息构建更多的更新和查询。当事务在时,可以保证其他人在工作进行当中无法作出更改。事实上,这不是 100% 的正确,但如果您之前没有过事务的话,这样介绍也未尝不可。
★预处理语句和存储过程
很多更成熟的数据库都支持预处理语句的概念。什么是预处理语句?您可以把预处理语句看作您想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句可以带来两大好处:
·&&&&&查询只需解析(或准备)一次,但是可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,这个过程要花比较长的时间,如果您需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/ 编译/优化周期。简言之,预处理语句使用更少的资源,因而运行得更快。
·&&&&&提供给预处理语句的参数不需要用引号括起来,驱动程序会处理这些。如果应用程序独占地使用预处理语句,那么可以确保没有 SQL 入侵发生。(然而,如果您仍然将查询的其他部分建立在不受信任的输入之上,那么就仍然存在风险)。
预处理语句是如此有用,以致 PDO 实际上打破了在目标 4 中设下的规则:如果驱动程序不支持预处理语句,那么 PDO 将仿真预处理语句。
实例:PDO的应用例子:
$dbms='mysql';//数据库类型
Oracle 用ODI,对于开发者来说,使用不同的数据库,只要改这个,不用记住那么多的函数了
$host='localhost';//数据库主机名
$dbName='test';//使用的数据库
$user='root';//数据库连接用户名
$pass='';//对应的密码
$dsn=&$dbms:host=$dbname=$dbName&;
classdbextendsPDO{
publicfunction__construct(){
parent::__construct(&$GLOBALS[dsn]&,$GLOBALS['user'],$GLOBALS['pass']);
}catch(PDOException$e){
die(&Error: &.$e-&__toString().&&br/&&);
publicfinalfunctionquery($sql){
returnparent::query($this-&setString($sql));
}catch(PDOException$e){
die(&Error: &.$e-&__toString().&&br/&&);
privatefinalfunctionsetString($sql){
echo&我要处理一下$sql&;
return$sql;
$db=newdb();
$db-&setAttribute(PDO::ATTR_CASE,PDO::CASE_UPPER);
foreach($db-&query('SELECT
* from xxxx_menu')as$row){
print_r($row);
$db-&exec('DELETE FROM `xxxx_menu` where mid=43');
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:959186次
积分:9314
积分:9314
排名:第1806名
原创:105篇
转载:121篇
评论:100条
(1)(2)(2)(7)(5)(7)(17)(17)(41)(21)(3)(18)(17)(20)(15)(29)(3)(1)PHP开发笔记系列(一)-PDO使用 - 移动生活=》移动未来 - ITeye技术网站
博客分类:
&&& 之前一段时间,开始了php的研究,看了关于PDO的一些资料,发现不错,整理和总结一下,作为开发笔记,留待日后使用,。
&&& PDO是PHP Data Objects的简称,是一种数据库访问抽象层。PDO是用于多种数据库的一致接口。类比的说,PDO做的事情类似于JAVA中的持久层框架(Hibernate、OpenJPA)的功能,为异构数据库提供一个统一的编程接口,这样就不必再使用mysql_*、pg_*这样的函数,也不必再写自己的"GenericDAO"了。PDO在PHP5.1的时候一起发布,所以我们用的PHP5.2、PHP5.3都已经可以使用。
&&& 为了方便,我们使用MySQL5来做演示。
0. 建立实验环境数据库及相关表
CREATE TABLE `blog` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1
1. 使用PDO访问数据库
&&& 通过PDO访问数据库的步骤是:a)指定dsn、username、password,b)通过#a中的设置构造PDO对象,代码如下:
file:pdo-access.php
url:http://localhost:88/pdo/pdo-access.php
// 设置dsn、username、passwd
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
// 构造PDO对象
$dbh = new PDO($dsn, $username, $passwd);
echo 'connect to database successfully!';
} catch (Exception $e) {
echo 'Fail to connect to database!\n';
echo $e-&getMessage();
&&& 备注:DSN即Data Source Name-数据源名称,提供数据库的连接信息,包括三部分,PDO驱动名称(MySQL、SQLite、PostgreSQL等)、冒号和驱动特定的语法。但是一般情况下,我们都很难记住这些,可以下载个php manual查,也可以到php的官网查。
2. 使用Query方法查询数据
&&& 在#1的基础上,连接数据库成功后,构造SQL语句,调用query方法返回结构数组,通过foreach进行数据结果遍历,代码如下:
file:pdo-query.php
url:http://localhost:88/pdo/pdo-query.php?title=title1
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$dbh = new PDO($dsn, $username, $passwd);
echo 'connect to database successfully!'."\r\n";
$title = 'title1';
// 构造SQL语句
$sql = "SELECT * FROM blog WHERE title = '".$title."'";
// 执行查询并遍历结果
foreach ($dbh-&query($sql) as $row){
print $row['id']."\t";
print $row['title']."\t";
} catch (PDOException $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
&&& 备注:一般情况下, 通过构造SQL语句的方法来进行query、update、insert、delete,都会需要指定where条件,因此不可避免的需要防止SQL注入的问题出现。
&&& 例如,正常情况下,当用户输入“title1”时,我们构造的sql语句会是SELECT * FROM blog WHERE title='title1',但是对SQL比较熟悉的用户会输入'OR id LIKE '%,此时我们构造的SQL就会变成SELECT * FROM blog where title='' OR id LIKE '%',这样整张blog 表中的数据都会被读取,因此需要避免,所以需要用到quote方法,把所有用户提供的数据进行转移,从而防止SQL注入的发生。使用quote方法后的sql为$sql = "SELECT * FROM blog WHERE title = ".$dbh-&quote($title),转移出来后的sql是SELECT * FROM blog WHERE title = '\'OR id LIKE \'%',把所有的单引号(')都转移了。
3. 使用prepare和execute方法查询数据
&&& 如果我们用到的SQL查询是使用频率不高的查询,那么使用query或prepare和execute方法来查询都无太大差别,查询速度也不会差太远。两者不同的是,使用query时,php向数据库发送的sql,每执行一次都需要编译一次,而使用prepare和execute方法,则不需要,因此做大并发量的操作时,使用prepare和execute方法的优势会更加明显。
&&& 使用prepare和execute方法的步骤不多,a)构造SQL,b)将SQL传入PDO-&prepart方法,得到一个PDOStatement对象,3)调用PDOStatement对象的execute方法,4)通过PDOStatement-&fetch或PDOStatement-&fetchObject遍历结果集。代码如下:
file:pdo-prepare-fetch.php
url:http://localhost:88/pdo/pdo-prepare-fetch.php?title=title1
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
// 从请求获取title参数值
$title = $_GET['title'];
$dbh = new PDO($dsn, $username, $passwd);
echo 'connect to database successfully!'."&br/&";
// 构造SQL语句,使用绑定变量
$sql = "SELECT * FROM blog WHERE title = :title";
// 编译SQL
$stmt = $dbh-&prepare($sql);
// 为绑定变量赋值
$stmt-&bindParam(":title", $title, PDO::PARAM_STR);
// 执行SQL
$stmt-&execute();
// 以联合数组方式获取结果,并遍历结果
while ($row = $stmt-&fetch(PDO::FETCH_ASSOC)) {
print $row['id']."\t";
print $row['title']."\t";
} catch (PDOException $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
&&& 除了使用上面的PDO::FETCH_ASSOC返回联合数组外,还可以使用fetchObject方法,返回结果集对象,代码如下:
file:pdo-prepare-fetch-object.php
url:http://localhost:88/pdo/pdo-prepare-fetch-object.php?title=title1
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$title = $_GET['title'];
$dbh = new PDO($dsn, $username, $passwd);
echo 'connect to database successfully!'."&br/&";
$sql = "SELECT * FROM blog WHERE title = :title";
$stmt = $dbh-&prepare($sql);
$stmt-&bindParam(":title", $title, PDO::PARAM_STR);
$stmt-&execute();
// 以对象数组方式获取结果,并遍历结果
while ($row = $stmt-&fetchObject()) {
print $row-&id."\t";
print $row-&title."\t";
} catch (Exception $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
4. 设置PDO的错误级别
&&& PDO的错误级别分成PDO::ERRMODE_SILENT(默认)、PDO::ERRORMODE_WARNING、PDO::ERRORMODE_EXCEPTION三种。
&&& PDO::ERRMODE_SILENT级别,当出现错误时,会自动设置PDOStatement对象的errorCode属性,但不进行任何其他操作,因此需要我们手工检查是否出现错误(使用empty($stmt-&errorCode())),否则程序将继续走下去。
&&& PDO::ERRORMODE_WARNING级别,基本与PDO::ERRMODE_SILENT一致,都是需要使用empty($stmt-&errorCode())手工检查。
&&& 只需要在创建PDO对象后,加入以下代码即可:$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);或$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
&&& PDO::ERRORMODE_WARNING级别,当出现错误时,系统将抛出一个PDOException,并设置errorCode属性,程序可以通过try{...}catch{...}进行捕捉,否则未catch的exception会导致程序中断,加入以下代码即可:$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $e) {
echo 'Errors occur when operation!'."&br/&";
// 获取Exception信息
echo $e-&getMessage()."&br/&";
// 获取错误码
echo $e-&getCode()."&br/&";
// 获取出错文件名
echo $e-&getFile()."&br/&";
// 获取出错行
echo $e-&getLine()."&br/&";
// 把异常以字符串返回
echo $e-&getTraceAsString();
5. 使用prepare和execute方法插入/更新数据
&&& 方法和#3中进行查询的差不多,只是构造的SQL语句是insert语句或update语句,代码如下:
file:pdo-prepare-insert.php
url:http://localhost:88/pdo/pdo-insert.php?title=title11
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$title = $_GET['title'];
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'connect to database successfully!'."&br/&";
// 构造Insert语句
$sql = "INSERT INTO blog(title) VALUES(:title)";
$stmt = $dbh-&prepare($sql);
$stmt-&bindParam(":title", $title);
$stmt-&execute();
} catch (Exception $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
file:pdo-prepare-update.php
url:http://localhost:88/pdo/pdo-update.php?id=1&title=title12
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$id = $_GET['id'];
$title = $_GET['title'];
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'connect to database successfully!'."&br/&";
// 构造update语句
$sql = "UPDATE blog SET title=:title where id=:id";
$stmt = $dbh-&prepare($sql);
$stmt-&bindParam(":id", $id);
$stmt-&bindParam(":title", $title);
$stmt-&execute();
} catch (Exception $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
6. 获取返回的行数
&&& 使用#3中的prepare和execute方法,然后将sql语句改成count的,例如SELECT COUNT(id) FROM article ...,代码如下:
file:pdo-prepare-fetch-column.php
url:http://localhost:88/pdo/pdo-prepare-fetch-column.php?id=1&title=title12
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
echo 'connect to database successfully!'."&br/&";
// 构造count语句
$sql = "SELECT COUNT(id) FROM blog";
$stmt = $dbh-&prepare($sql);
$stmt-&execute();
// 使用fetchColumn获取0列值
echo $stmt-&fetchColumn()." rows returned!";
} catch (Exception $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
7. 获取受影响的行数
&&& 使用#3中的prepare和execute方法,然后将SQL语句改成insert、update、delete语句即可,代码如下:
file:pdo-prepare-row-count.php
url:http://localhost:88/pdo/pdo-prepare-row-count.php?id=1
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$id = $_GET['id'];
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
echo 'connect to database successfully!'."&br/&";
$sql = "DELETE FROM blog WHERE id=:id";
$stmt = $dbh-&prepare($sql);
$stmt-&bindParam(":id", $id);
$stmt-&execute();
// 获取update、insert、delete操作后影响的行数
echo $stmt-&rowCount()." rows affected!";
} catch (Exception $e) {
echo 'Errors occur when data operation!\n';
echo $e-&getMessage();
8. 获得新插入行的ID值
&&& 为数据库表插入新数据行时,我们需要获得刚刚插入的新行的ID值,此时我们需要使用到PDO的lastInsertId()方法,代码如下:
file:pdo-prepare-last-insertid.php
url:http://localhost:88/pdo/pdo-prepare-last-insertid.php?title=title13
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$title = $_GET['title'];
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'connect to database successfully!'."&br/&";
$sql = "INSERT INTO blog(title) VALUES(:title)";
$stmt = $dbh-&prepare($sql);
$stmt-&bindParam(":title", $title);
$stmt-&execute();
// 获取上一个之行的insert语句插入的数据的id值
echo $dbh-&lastInsertId();
} catch (Exception $e) {
echo 'Errors occur when query data!\n';
echo $e-&getMessage();
9. 使用PDO进行事务管理
&&& 事务是进行程序开发时,保证数据ACID(可分性、一致性、独立性、持久性)的工具。要不全部成功,要不全部不成功,这样才能保证关联数据的保存能够达到预期的目的。下面使用PDO的Transaction来进行实验,进行多比数据插入,开启事务,第一句sql是可以正常插入,第二句sql插入出错,检查是否rollback。
file:pdo-prepare-transaction.php
url:http://localhost:88/pdo/pdo-prepare-transaction.php
$dsn = 'mysql:host=dbname=pdotest';
$username = 'root';
$passwd = 'password';
$dbh = new PDO($dsn, $username, $passwd);
$dbh-&setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo 'connect to database successfully!'."&br/&";
// 开启事务
$dbh-&beginTransaction();
$sql = "INSERT INTO blog(title) VALUES(:title)";
$stmt = $dbh-&prepare($sql);
$stmt-&execute(array(':title'=&'insert title1'));
$stmt-&execute(array(':title'=&NULL));
// 提交事务
$dbh-&commit();
} catch (Exception $e) {
echo 'Errors occur when data operation!\n';
echo $e-&getMessage();
// 回滚事务
$dbh-&rollBack();
10. 使用PDO进行数据库备份
&&& 使用system函数,将我们构造的mysqldump命令传入即可。下面为了演示,只做了简单的调用。
file:pdo-backup.php
url:http://localhost:88/pdo/pdo-backup.php
$username="root";
$passwd="password";
$dbname="pdotest";
$file='d:/'.$dbname.'.sql';
// 构造备份命令
$cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." &".$
// 执行备份命令
system($cmd,$error);
if($error){
trigger_error("backup failed".$error);
&&& 采用工厂模式:
file:AbstractMySQLDump.php
require_once 'MySQLDump_Win.php';
abstract class AbstractMySQLDump {
protected $
abstract function __construct($username, $passwd, $dbname, $file);
// 依据操作系统类型,使用工厂方法构造备份类
public static function factory($username, $passwd, $dbname, $file){
if(strtoupper(substr(PHP_OS, 0, 3))==='WIN'){
return new MySQLDump_Win($username, $passwd, $dbname, $file);
implement MySQLDump_NIX($username, $passwd, $dbname, $file);
// 备份逻辑
public function backup(){
system($this-&cmd, $error);
// 判断是否出错及出错逻辑
if($error){
trigger_error("backup failure! command:".$this-&cmd." Error:".$error);
file:MySQLDump_Win.php
class MySQLDump_Win extends AbstractMySQLDump {
// 覆盖父类的构造方法
public function __construct($username, $passwd, $dbname, $file){
$this-&cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." & ".$
file:MySQLDumpTest.php
url:http://localhost:88/pdo/MySQLDumpTest.php
require_once 'AbstractMySQLDump.php';
$username = "root";
$passwd = "password";
$dbname = "pdotest";
$file = "d:/".$dbname.".sql";
// 使用工厂方法生成备份类
$dump = AbstractMySQLDump::factory($username, $passwd, $dbname, $file);
// 执行备份类的backup方法
$dump-&backup();
&&& 本文地址: http://ryan-/blog/1543225
下载次数: 26
浏览: 46946 次
来自: 广州}

我要回帖

更多关于 数据库有哪些 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信