作者: mzt
出自:
http://www.phpchina.cnPHP 5.1 发布时附带一个全新的数据库连接层,即 PHP Data Objects (PDO)。它与ADODB和Pear DB等数据库抽象层不同,它提供的是如何存取数据库和处理查询结果,效率也更高,还可以通过预处理语句来防止sql注入。
目前支持的数据库有:
• DBLIB: FreeTDS / Microsoft SQL Server / Sybase
• Firebird (
http://firebird.sourceforge.net/): Firebird/Interbase 6
• MYSQL (
http://www.mysql.com/): MySQL 3.x/4.x
• OCI (
http://www.oracle.com): Oracle Call Interface
• ODBC: ODBC v3 (IBM DB2 and unixODBC)
• PGSQL (
http://www.postgresql.org/): PostgreSQL
• SQLITE (
http://www.postgresql.org/): SQLite 3 and SQLite 2
1. 连接数据库
通常我们连接数据库使用的是不同的连接函数(如:mysql_connect,pg_connect),PDO提供了统一的接口:PDO对象。
$db = new PDO(
"pgsql:dbname=pdo;host=localhost",
"postgres8",
"postgres8"
);
echo "Successfully created a PDO object";
?>
就像你看到的,PDO有三个参数,
• 连接字符串
pgsql 是使用的PDO驱动,可以为:mysql, mssql, sybase, dblib, firebird, oci, odbc, pgsql, sqlite, sqlite2;
dbname 是数据库名称,这里假设有一个名为pdo的测试数据库;
host 是指要连接到哪里,如果是本地则为localhost。
• 用户名
• 密码
做这一步之前,请先确认已经加载了PDO模块。如果我们试图处理一个无效的连接字符串:
$db = new PDO(
"THIS_IS_NOT_A_PDO_MODULE:dbname=pdo;host=localhost",
"foo",
"bar"
);
echo "Successfully created a PDO object";
?>
PHP将会返回以下错误:
Fatal error: Uncaught exception 'PDOException' with message 'could not find driver'
所以,我们可以用一种优雅的方式来处理,即抛出PDO异常来处理错误(但并不是所有情况都是)。
try
{
$db = new PDO(
"THIS_IS_NOT_A_PDO_MODULE:dbname=pdo;host=localhost",
"postgres8",
"postgres8"
);
}
catch( PDOException $e )
{
die( $e->getMessage() );
}
echo "Successfully created a PDO object";
?>
我们会得到
could not find driver
或
SQLSTATE[HY000] [7] FATAL: database "pdo2" does not exist
如果数据库不存在(不同的错误会返回不同的提示信息)。
2. 设置属性
1) PDO有三种错误处理方式:
• PDO::ERRMODE_SILENT不显示错误信息,只设置错误码
• PDO::ERRMODE_WARNING显示警告错
• PDO::ERRMODE_EXCEPTION抛出异常
可通过以下语句来设置错误处理方式为抛出异常
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
当设置为PDO::ERRMODE_SILENT时可以通过调用errorCode() 或errorInfo()来获得错误信息,当然其他情况下也可以。
2) 因为不同数据库对返回的字段名称大小写处理不同,所以PDO提供了PDO::ATTR_CASE设置项(包括PDO::CASE_LOWER,PDO::CASE_NATURAL,PDO::CASE_UPPER),来确定返回的字段名称的大小写。
3) 通过设置PDO::ATTR_ORACLE_NULLS类型(包括PDO::NULL_NATURAL,PDO::NULL_EMPTY_STRING,PDO::NULL_TO_STRING)来指定数据库返回的NULL值在php中对应的数值。
3. 查询
为了说明清楚,我们这里定义了一个RSS feeds表
id integer
name character varying(100)
url varharacter varying(255)
feed character varying(255)
不使用预处理语句的方式:
foreach( $db->query( "SELECT * FROM feeds" ) as $row )
{
print_r( $row );
}
?>
得到以下结果:
Array
(
[id] => 1
[0] => 1
[name] => Planet-PHP
[1] => Planet-PHP
[url] =>
http://www.planet-php.net[2] =>
http://www.planet-php.net[feed] =>
http://www.planet-php.net/rdf/[3] =>
http://www.planet-php.net/rdf/)
(只显示已行为了节省空间)
使用预处理语句的方式:
$stmt = $db->prepare( "SELECT * FROM feeds" );
$stmt->execute();
print_r( $stmt->fetch() );
?>
这里,$stmt是一个PDOStatement对象,预处理之后会得到这样一个对象,必须execute后才起作用。fetch函数只提取了一行数据,如果需要读取全部数据,可换成fetchAll函数。
绑定数据
$stmt = $db->prepare( "SELECT * FROM feeds WHERE url = :url" );
$url = "
http://www.planet-php.net";
$stmt->bindParam( ":url", $url );
$stmt->execute();
while( $row = $stmt->fetch() )
{
print_r( $row );
}
?>
这里,bindParam将$url变量绑定到了:url域,执行时会自动将改变量载入。
插入数据
$stmt = $db->prepare(
"INSERT INTO feeds
( name, url, feed )
VALUES
( :name, :url, :feed )"
);
$stmt->execute(
array(
":name" => "Planeti Apache",
":url" => "
http://www.planetapache.org",
":feed" => "
http://www.planetapache.org/rss10.xml"
)
);
?>
实现插入数据也可以像绑定数据一样来quote数据,这里给出通过在execute中给定输入参数来自动quote的方法。
事务处理
$dbh->beginTransaction();
try {
$dbh->query("UPDATE ...");
$dbh->query("UPDATE ...");
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
}
如果数据库支持事务处理,调用beginTransaction的同时将数据库设置为非自动提交,commit或rollBack返回自动提交状态。
4. 存储过程
$stmt = $dbh->prepare("CALL sp_set_string(?)");
$stmt->bindParam(1, $str);
$str = ‘foo’;
$stmt->execute();
于先前的例子差不多,只是这里使用了“?”数据绑定方法,sp_set_string是存储过程名称。
带有输出参数的存储过程
$stmt = $dbh->prepare("CALL sp_get_string(?)");
$stmt->bindParam(1, $ret,PDO:ARAM_STR, 4000);
if ($stmt->execute()) {
echo "Got $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";
}
}