目錄 1. PHP數據庫驅動簡介 2. PHP連接數據庫的不同方式 1. PHP數據庫驅動簡介 驅動是一段設計用來於一種特定類型的數據庫服務器進行交互的軟件代碼。驅動可能會調用一些庫。類似於Java中的數據庫驅動的概念 復制代碼 1. JDBC-ODPC橋: 它將JDBC API映射到ODPC API。再讓JDBC-ODPC調用數據庫本地驅動代碼(也就是數據庫廠商提供的數據庫操作二進制代碼庫,例如Oracle中的oci.dll) 2. 本地API驅動 直接將JDBC API映射成數據庫特定的客戶端API,即通過客戶端加載數據庫廠商提供的本地代碼庫(C/C++等) 3. 網絡協議驅動(主流) 這種類型的驅動給客戶端提供了一個網絡API,客戶端上的JDBC驅動程序使用套接字(Socket)來調用服務器上的中間件程序,後者在將其請求轉化為所需的具體API調用。 4. 本地協議驅動(主流) 這種類型的驅動使用Socket,直接在客戶端和數據庫間通信。它是一種直接與數據庫實例交互的JDBC 這種驅動是智能的,它知道數據庫使用的底層協議,也是目前最主流使用的JDBC驅動,我們本章的重點就是它 復制代碼 而對於PHP來說,同樣主流使用的也是網絡協議驅動、本地協議驅動,即MySQL客戶端庫、MySQL Native驅動庫。 這些庫實現了用於和MySQL數據庫服務器進行交互的底層協議。 數據庫驅動位於PHP和數據庫進行通信的最底層,不同的數據庫廠商都會在基於某個框架的前提下實現自己的驅動,用以提供基本功能、以及特定數據庫的高級功能。 在驅動層之上是"連接器"、或者是適配器抽象層,用於PHP代碼和數據庫進行連接,程序員可以使用PDO(PHP Database Object)、或者直接使用擴展接口(mysql、mysqli)這些暴露出來的API與底層數據庫進行通信。 數據庫廠商提供的底層數據庫驅動 mysql: http://www.mysql.com/products/connector/ oracle: http://www.oracle.com/technetwork/indexes/downloads/index.html#database sqlserver: http://msdn.microsoft.com/zh-cn/library/cc296170(SQL.90).aspx ... 文件型數據庫 文件型是一種基於文件的數據庫引擎,而且使用文件I/O(輸入/輸出)函數來存儲和讀取來自磁盤上文件的數據庫。它普遍也比關系型數據庫(例如Mysql)小很多很多(例如典型的文件型數據庫 SQLite命令行版本的大小小於200KB),同時,文件型數據庫而且支持你所熟悉的大部分SQL命令,同時具有易於攜帶的特點 接下來,我們以上面這張大圖作為開始,逐一學習PHP連接數據庫的不同方式、以及它們在不同業務場景下的優缺點 2. PHP連接數據庫的不同方式 0x1: 使用擴展API接口與數據庫通信 PHP代碼是由一個核心,一些可選擴展組成了核心功能。PHP 的MySQL相關擴展,比如mysqli,mysql都是基於PHP擴展框架實現的。 擴 展一個典型的作用就是暴露一個API給PHP程序員,允許擴展自己的功能可以被程序員使用。當然,也有一部分基於PHP擴展框架 開發的擴展不會給PHP程序員暴露API接口。比如說PDO MySQL驅動擴展,就沒有向PHP程序員暴露API接口,但是向它上層的PDO層提供了一個接口。 關於PHP擴展的編寫請參閱另一篇博文 http://www.cnblogs.com/LittleHann/p/3562259.html 在實際編程中,使用頻度最多的還是以擴展API的方式去連接數據庫 extension=php_mysql.dll 這 是設計開發允許PHP應用與MySQL數據庫交互的早期擴展。mysql擴展提供了一個面向過程的接口,並且是針對MySQL4.1.3或更早版本設計 的。因此,這個擴展雖然可以與MySQL4.1.3或更新的數據庫服務端 進行交互,但並不支持後期MySQL服務端提供的一些特性 mysql擴展的源代碼在PHP擴展目錄ext/mysql下 復制代碼 <?php // 連接、選擇數據庫 $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password') or die('Could not connect: ' . mysql_error()); echo 'Connected successfully'; mysql_select_db('my_database') or die('Could not select database'); // 執行 SQL 查詢 $query = 'SELECT * FROM my_table'; $result = mysql_query($query) or die('Query failed: ' . mysql_error()); // 以 HTML 打印查詢結果 echo "<table>\n"; while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) { echo "\t<tr>\n"; foreach ($line as $col_value) { echo "\t\t<td>$col_value</td>\n"; } echo "\t</tr>\n"; } echo "</table>\n"; // 釋放結果集 mysql_free_result($result); // 關閉連接 mysql_close($link); ?> 復制代碼 extension=php_mysqli.dll mysqli擴展,我們有時稱之為MySQL增強擴展,可以用於使用MySQL4.1.3或更新版本中新的高級特性。mysqli擴展在PHP 5及以後版本中包含。 mysqli擴展有一系列的優勢,相對於mysql擴展的提升主要有: 復制代碼 1. 面向對象接口 2. prepared語句支持(即參數編譯預處理,可以有效防御SQL注入的發生) 3. 多語句執行支持 4. 事務支持 5. 增強的調試能力 6. 嵌入式服務支持 7. 在提供了面向對象接口的同時也提供了一個面向過程的接口。 復制代碼 mysqli擴展是使用PHP擴展框架構建的,它的源代碼在PHP源碼目錄下的ext/mysqli中 復制代碼 <?php $con = new mysqli("localhost", "root", "111", "php4fun_"); /* check connection */ if (mysqli_connect_errno()) { printf("Connect failed: %s\n", mysqli_connect_error()); exit(); } $sql = "select name from users where name = ? and pass = ?"; $cmd = $con->prepare($sql); $name = $_GET['name']; $pass = $_GET['pass']; //add parameters to sql query $cmd->bind_param("ss", $name, $pass); $cmd->execute(); $cmd->bind_result($result); $cmd->fetch(); if($result) { var_dump($result); } ?> 復制代碼 mysqli除了可以使用參數編譯預處理來進行數據庫通信,同時也兼容使用面向過程的編碼方式 復制代碼 <?php /* Connect to a MySQL server 連接數據庫服務器 */ $link = mysqli_connect( 'localhost', /* The host to connect to 連接MySQL地址 */ 'root', /* The user to connect as 連接MySQL用戶名 */ '111', /* The password to use 連接MySQL密碼 */ 'company'); /* The default database to query 連接數據庫名稱*/ if (!$link) { printf("Can't connect to MySQL Server. Errorcode: %s ", mysqli_connect_error()); exit; } /* Send a query to the server 向服務器發送查詢請求*/ if ($result = mysqli_query($link, 'SELECT * from p8_ad_user')) { print("Very large cities are: "); /* Fetch the results of the query 返回查詢的結果 */ while( $row = mysqli_fetch_assoc($result) ) { printf("%s (%s) ", $row['Name'], $row['Population']); } /* Destroy the result set and free the memory used for it 結束查詢釋放內存 */ mysqli_free_result($result); } /* Close the connection 關閉連接*/ mysqli_close($link); ?> 復制代碼 PHP還支持很多其他的數據庫連接擴展,使用方法都類似,只要遵循函數調用規范即可,更多詳情請參閱 http://www.php.net/manual/zh/refs.database.php 0x2: 使用PDO抽象層與數據庫通信 PDO(PHP 數據對象 PHP Database Object),是PHP應用中的一個數據庫抽象層規范。PDO提供了一個統一的API接口可以使得你的PHP應用不去關心具體要連接的數據庫服務器系統 類型。也就是說,如果你使用PDO的API,可以在任何需要的時候無縫切換數據庫服務器,比如從Firebird到MySQL,僅僅需要修改很少的PHP 代碼。 其他數據庫抽象層的例子包括Java應用中的JDBC以及Perl中的DBI。 注意: 利用 PDO 擴展自身並不能實現任何數據庫功能;必須使用一個具體數據庫的PDO驅動來訪問數據庫服務(它只是一個接口規范) 但是反過來說,一個接口提供的兼容性越強,它的定制性、特異性就相應越弱(這很容易理解),PDO接口API的主要缺點是會限制讓你不能使用MySQL服務端提供所有的數據庫高級特性。比如,PDO不允許使用MySQL支持的多語句執行。 在PHP5中,PDO目前已經支持大量數據庫,並且在PHP6中將作為默認數據庫連接方式: 1. sqlite 2. mysql 3. pgsql 4. mssql ... PDO是基於PHP擴展框架實現的,它的源碼在PHP源碼目錄的ext/pdo下 再次強調,PDO只是一個接口規范,它自身並不實現任何的數據庫功能,程序員必須使用一個具體數據庫的"PDO驅動"來訪問特定的數據庫 extension=php_pdo_mysql.dll 復制代碼 <?php $dbhost="localhost"; $dbname="company"; $dbusr="root"; $dbpwd="111"; $dbhdl=NULL; $dbstm=NULL; $opt = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',); $dsn='mysql:host=' . $dbhost . ';port=3306;dbname=' . $dbname; try { $dbhdl = new PDO($dsn, $dbusr, $dbpwd, $opt); //Display exception $dbhdl->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); } catch (PDOExceptsddttrtion $e) { //return PDOException print "Error!: " . $e->getMessage() . "<br>"; die(); } $dbstm = $dbhdl->query('SELECT * from p8_ad_user LIMIT 0,1'); $rows = $dbstm->fetchAll(PDO::FETCH_ASSOC);//$rows = $dbhdl->Fetch(); print_r($rows); ?> 復制代碼 extension=php_pdo_pgsql.dll 復制代碼 <?php $host = "localhost"; $user = "root"; $pass = "111"; $db = "company"; $cursor = "cr_123456"; try { $dbh = new PDO("pgsql:host=$host;port=5432;dbname=$db;user=$user;password=$pass"); echo "Connected<p>"; } catch (Exception $e) { echo "Unable to connect: " . $e->getMessage() ."<p>"; } $dbh->beginTransaction(); $query = "SELECT * from p8_ad_user LIMIT 0,1"; $dbh->query($query); $query = "FETCH ALL IN \"$cursor\""; echo "begin data<p>"; foreach ($dbh->query($query) as $row) { echo "$row[0] $row[1] $row[2] <br>"; } echo "end data"; ?> 復制代碼 這裡只以Mysql、PostGreSQL為例,事實上,PDO這種抽象層方式可以訪問目前主流的大多數的數據庫,並且PDO將成為PHP6的默認數據庫連接方式,更多詳情請參閱 http://www.php.net/manual/zh/book.pdo.php 0x3: 使用ODBC抽象層與數據庫通信 ODBC是一種應用程序編程接口(Application Programming Interface,API),使我們有能力連接到某個數據源(比如一個MS Access 數據庫) 試圖通過編程語言和數據庫查詢訪問(SQL標准化)來標准化連接方法,比如功能和配置。 ODBC的作用是充當接口或連接器,它具有雙重設計目標: 1. 首先,對於ODBC 系統,它充當的是編程語言系統 2. 其次,對於數據存儲系統,它充當的是 ODBC 系統。 所 以,ODBC 需要一個"對ODBC而言是編程語言"的驅動程序(例如PHP-ODBC庫)和一個"對數據存儲系統而言是ODBC"的驅動程序(比如 MySQL-ODBC庫)。除了ODBC系統本身之外,ODBC還可以處理數據源的配置,允許數據源和編程語言之間存在模糊性。 和之前學習的擴展API接口、PDO略有不同的是,使用ODBC連接數據庫要稍微麻煩一點(至少我個人這麼覺得),這個"麻煩"體現在我們需要對目標數據庫服務器的操作系統進行一些配置,即創建ODBC數據源,然後才可以進行ODBC連接 創建到達 MS Access 數據的 ODBC 連接的方法: 復制代碼 1. 在控制面板中打開管理工具 2. 雙擊其中的數據源 (ODBC)圖標 3. 選擇系統 DSN 選項卡 4. 點擊系統 DSN 選項卡中的"添加"按鈕 5. 選擇 Microsoft Access Driver。點擊完成 6. 在下一個界面,點擊“選擇”來定位數據庫 7. 為這個數據庫取一個數據源名 (DSN) 8. 點擊確定 復制代碼 code: 復制代碼 <html> <body> <?php //連接一個ODBC數據源,無帳號、密碼 $conn = odbc_connect('northwind', '', ''); if (!$conn) { exit("Connection Failed: " . $conn); } $sql = "SELECT * FROM p8_ad_user"; $rs = odbc_exec($conn, $sql); if (!$rs) { exit("Error in SQL"); } echo "<table><tr>"; echo "<th>Companyname</th>"; echo "<th>Contactname</th></tr>"; while (odbc_fetch_row($rs)) { $username = odbc_result($rs, "username"); $password = odbc_result($rs, "password"); echo "<tr><td>$username</td>"; echo "<td>$password</td></tr>"; } odbc_close($conn); echo "</table>"; ?> </body> </html> 復制代碼 0x4: 使用DBX與數據庫通信 PHP本身內置了DBX函數,DBX模塊是一個數據庫抽象層(DBX中的"X"就表示其所能支持的X種數據庫)。DBX函數允許你訪問所有DBX支持的數據庫。 DBX支持下列數據庫: 1. Mysql 2. ODBC 3. PgSQL 4. Mssql(Microsoft SQL Server) 5. Fbsql download: http://pecl.php.net/package/dbx http://rpmfind.net/linux/rpm2html/search.php?query=php-dbx code: 復制代碼 <html> <head> <title>A PHP-DBX URL Organizer</title> <style type=text/css> p, ul, td, h1, h2, h3 { font-family: verdana, helvetica, sans-serif; } </style> </head> <body> <? /***** * TABLE DEFINITION FOR THIS EXAMPLE: * create table URLS ( * url VARCHAR(128) not null, * description TEXT, * primary key (url)); *****/ //define $MODULE as DBX_MYSQL, DBX_MSSQL, DBX_PGSQL, or your supported database $MODULE = DBX_PGSQL; $server = "localhost"; $user = "root"; $password = "111"; $database = "company"; /* FUNCTIONS */ function get_urls($dbconn, $sql) { $result = @dbx_query($dbconn, $sql); if ( $result == 0 ) { echo dbx_error($dbconn); } else { return $result; } } function url($action, $dbconn, $url, $description) { if($action == "add") { $sql = "insert into URLS values('$url', '$description')"; } elseif($action == "delete") { $url = urldecode($url); $sql = "delete from URLS where URL = '$url'"; } $result = @dbx_query($dbconn, $sql); if ( $result == 0 ) { echo "<P>ERROR ADDING URL: " . dbx_error($dbconn); } else { print("<p>$action : $url succeeded!<p>"); } } /*** MAIN ***/ $dbconn = dbx_connect($MODULE, $server, $database, $user, $password) or die("CANNOT CONNECT TO DATABASE"); ?> <h1>PHP DBX URL Organizer</h1> <form action=dbx_urls.php method=post> <p><b>Add a URL:</b> <br>URL: <input type="text" name="url" maxlength="128" value="http://"> Description: <input type="text" name="description"> <input type="submit" name="addurl" value="Add URL!"> </form> <? if(isset($addurl)) { url("add", $dbconn, $url, $description); } if(isset($delete)) { url("delete", $dbconn, $delete, ""); } $sql = "select * from URLS"; $result = get_urls($dbconn, $sql); if(sizeof($result->data) == 0) { ?> <h3>Sorry, there are no URLs in the database. You should add some. <? } else { ?> <p> <table border=1 cellpadding=5 cellspacing=0 width=600> <tr><td><b>URL</b></td><td> <b>Description</b></td><td> </td></tr> <? for($i = 0; $i < sizeof($result->data); $i++) { ?> <tr><td><a href=<?=$result->data[$i]['url']?>><?=$result->data[$i]['url']?></a></td> <td><?=$result->data[$i]['description']?></td> <td width=1><a href=dbx_urls.php?delete=<?=urlencode($result->data[$i]['url'])?>>delete</a></tr> <? } ?></table> <? } ?> </body> </html> 復制代碼 0x5: 使用DBA(Database (dbm-style) Abstraction Layer)與數據庫通信 PHP的DBA抽象層是用來支持Berkeley DB這種文件型數據庫的。 These functions build the foundation for accessing Berkeley DB style databases. 在柏克萊的BSD系列操作系統中,有個簡單的數據庫結構,它以數個文件組成超小型的數據庫系統,架構成抽象層(abstraction layer)的DBA數據庫。 目前PHP支持的DBA數據庫包括 復制代碼 1. DBM: 柏克萊發展的最早期DBA數據庫 http://en.wikipedia.org/wiki/Dbm 2. NDBM: 較新且較有彈性的DBA http://en.wikipedia.org/wiki/NDBM 3. GDBM: GNU 發展的DBA ftp://ftp.gnu.org/pub/gnu/gdbm/ 4. DB2: 由Sleepycat軟件開發的DB2(非IBM的DB2) http://www.openldap.org/lists/openldap-software/199905/msg00009.html 5. CDB: 這是qmail作者開發快速可靠的DBA http://pobox.com/~djb/cdb.html 復制代碼 安裝好DBA後,使用如下代碼進行連接 復制代碼 <?php $id = dba_open ( "/tmp/test.db" , "n" , "db2" ); if(! $id ) { echo "dba_open failedn" ; exit; } dba_replace ( "key" , "This is an example!" , $id ); if( dba_exists ( "key" , $id )) { echo dba_fetch ( "key" , $id ); dba_delete ( "key" , $id ); } dba_close ( $id ); ?> 復制代碼 3. 後記 以上就是PHP連接數據庫的不同方式的學習,通過本文的學習,我們了解到一點 目前PHP開發中主流使用的連接數據庫的技術是 1. Mysql擴展API 2. Mysqli擴展API 3. PDO抽象層 下一步希望做的事 1. 研究一下PHP和mysql進行交互的協議驅動的底層原理 2. 嘗試編程簡單的通信協議驅動