PDO詳解


PDO擴展爲PHP定義了一個訪問數據庫的輕量的,持久的接口。實現了PDO接口的每一種數據庫驅動都能以正則擴展的形式把他們各自的特點表現出來。注意;利用PDO擴展自己並不能實現任何數據庫函數。你必須使用一個特定的數據庫PDO驅動去訪問數據庫。
PDO提供了一個數據訪問抽象層,這就意味着,無論你使用的是哪一種數據庫,你均可以用一樣的函數去進行查詢的獲取數據。PDO並不提供數據提取,它不會重寫SQL語句,或者模仿這些功能。你須要使用一個成熟的提取層,若是你須要的話。
php

怎麼樣,是否是看了譯文就有一種恍然大悟的感受了?
沒有?
那說的再詳細點。
咱們爲何要使用PDO?
一、更換數據庫時取得極大便利
在PHP4/3時代,PHP要利用php_mysql.dll、php_pgsql.dll、php_mssql.dll、 php_sqlite.dll等等擴展來鏈接MySQL、PostgreSQL、MS SQL Server、SQLite,這其實也沒什麼。也就是在配置時多添句話就好了。
可怕的是,這些擴展和各自對應的數據庫打交道時,他們各自的函數有不少是不同的。
好比:
PHP利用libmysql.dll和MYSQL打交道時,若是要從數據表中提取數據做爲關聯數組,用的是mysql_fetch_accoc,而若是要從postgre數據庫取得一樣的結果,你就不得不用pg_fetch_assoc。
很簡單的例子說明了很重要的問題,假如你要更換數據庫類型,好比從MYSQL更換成POSTGRE,你就不得把你全部和數據庫有關的程序都改一遍。這時候,你應該會明白,爲何我不用PDO??
二、極大提升程序運行效率
針對上面的狀況,也許你會說,我可使用ADODB(LITE),PEAR::db來實現對不一樣類型數據庫函數的封裝啊。這樣子,即便我更換數據庫,也不須要修改程序。
答:php代碼的效率怎麼可以和直接用C/C++寫的擴展效率比較呢?根本不是一個數量級的。
OK,從如今開始用PDO進行你的開發吧。
mysql

安裝 sql

PDO擴展爲PHP訪問數據庫定義了一個輕量級的、一致性的接口,它提供了一個數據訪問 抽象層,這樣,不管你使用什麼數據庫,你均可以經過一致的函數執行查詢和獲取數據。注意,你並不能使用PDO擴展自己執行任何數據庫操做,你必須使用一個database-specific PDO driver (針對特定數據庫的PDO驅動)訪問數據庫服務器。數據庫

PDO並 提供數據庫 抽象,它並不會重寫SQL或提供數據庫自己缺失的功能,若是你須要這種功能,你須要使用一個更加成熟的抽象層。數組

PDO隨PHP5.1發行,在PHP5.0的PECL擴展中也可使用。PDO須要PHP5核心OO特性的支持,因此它沒法運行於以前的PHP版本。緩存

 

在Unix環境下PHP5.1以上版本中:安全

  1. 若是你正在使用PHP5.1版本,PDO和PDO SQLITE已經包含在了此發行版中;當你運行configure時它將自動啓用。推薦你將PDO做爲共享擴展構建,這樣可使你得到經過PECL升級的 好處。推薦的構建支持PDO的PHP的configure line應該也要啓用zlib。你也應該啓用你選擇的數據庫的PDO驅動 ;關於這個的更多信息請查看database-specific PDO drivers ,但要注意若是你將PDO做爲一個共享擴展構建,你必須也要將PDO驅動構建爲共享擴展。SQLite擴展依賴於PDO,因此若是PDO做爲共享擴展構建,SQLite也應當這樣構建
    ./configure --with-zlib --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared    
  2. 將 PDO安裝爲一個共享模塊後,你必須編輯php.ini文件使得在PHP運行時自動載入PDO擴展。你一樣須要啓用那兒的特定數據庫 驅動;確保他們列出在 pdo.so  行以後,由於PDO必須在特定數據庫驅動載入以前初始化。若是你是以靜態方式構建的PDO和特定數據庫驅動擴展,你能夠跳過這一步。
    Php代碼   收藏代碼
    1. extension=pdo.so  
     
  3. 讓PDO做爲一個共享的模塊將使你能夠在新版PDO發佈時運行 pecl upgrade pdo  命令升級,而不用強制你從新構建整個PHP。注意若是你是這樣作的,你也須要同時升級你的特定數據庫驅動。

在Windows環境下PHP5.1以上版本中:服務器

  1. PDO和主要數據庫的驅動同PHP一塊兒做爲擴展發佈,要激活它們只需簡單的編輯php.ini文件:
    Php.ini代碼   收藏代碼
    1. extension=php_pdo.dll   
     
  2. 而後,選擇針對特定數據庫的DLL文件使用 dl() 在運行時加載,或者在php.ini文件中 php_pdo.dll 行後啓用它們,如:
    Php.ini代碼   收藏代碼
    1. extension=php_pdo.dll  
    2. extension=php_pdo_firebird.dll  
    3. extension=php_pdo_informix.dll  
    4. extension=php_pdo_mssql.dll  
    5. extension=php_pdo_mysql.dll  
    6. extension=php_pdo_oci.dll  
    7. extension=php_pdo_oci8.dll  
    8. extension=php_pdo_odbc.dll  
    9. extension=php_pdo_pgsql.dll  
    10. extension=php_pdo_sqlite.dll  
     
    這些DLL文件應當存在於系統的 extension_dir 目錄裏。注意 PDO_INFORMIX 只能做爲一個PECL擴展使用。

修改php.ini後重啓http服務器。函數

OK,PDO安裝完畢。post

PDO中包含三個預約義的類

PDO中包含三個預約義的類,它們分別是 PDO PDOStatement  PDOException ,下面將分別簡單介紹一下。後面的系列相關文章會使用若干示例介紹這幾個類的使用。

1、PDO
表明一個PHP和數據庫之間的鏈接。

方法:

  1. PDO - 構造器,構建一個新的PDO對象
  2. beginTransaction - 開始事務
  3. commit - 提交事務
  4. errorCode - 從數據庫返回一個錯誤代號,若是有的話
  5. errorInfo - 從數據庫返回一個含有錯誤信息的數組,若是有的話
  6. exec - 執行一條SQL語句並返回影響的行數
  7. getAttribute - 返回一個數據庫鏈接屬性
  8. lastInsertId - 返回最新插入到數據庫的行(的ID)
  9. prepare - 爲執行準備一條SQL語句,返回語句執行後的聯合結果集(PDOStatement)
  10. query - 執行一條SQL語句並返回一個結果集
  11. quote - 返回添加了引號的字符串,以使其可用於SQL語句中
  12. rollBack - 回滾一個事務
  13. setAttribute - 設置一個數據庫鏈接屬性

 

Php代碼   收藏代碼
  1. /* 經過 ODBC 驅動創建數據庫鏈接 */     
  2. $dsn  =  'mysql:dbname=testdb;host=127.0.0.1' ;    
  3. $user  =  'dbuser' ;    
  4. $password  =  'dbpass' ;    
  5. try {    
  6.   $dbh  =  new  PDO( $dsn ,  $user ,  $password );    
  7. } catch (PDOException $e ) {    
  8.   echo   'Connection failed: '  .  $e ->getMessage();    
  9. }    
  10. /* 事務處理開始,關閉自動提交事務(autocommit) */     
  11. $dbh ->beginTransaction();    
  12. /* 更改數據庫結構 */     
  13. $sth  =  $dbh -> exec ( "DROP TABLE fruit" );    
  14. /* 提交事務 */     
  15. $dbh ->commit();    
  16. /* Database connection is now back in autocommit mode */   

 



2、PDOStatement
表明一條預處理語句以及語句執行後的聯合結果集(associated result set)。

方法:

  1. bindColumn - 綁定一個PHP變量到結果集中的輸出列
  2. bindParam - 綁定一個PHP變量到一個預處理語句中的參數
  3. bindValue - 綁定一個值到與處理語句中的參數
  4. closeCursor - 關閉遊標,使語句能夠再次執行
  5. columnCount - 返回結果集中的列的數量
  6. errorCode - 從語句中返回一個錯誤代號,若是有的話
  7. errorInfo - 從語句中返回一個包含錯誤信息的數組,若是有的話
  8. execute - 執行一條預處理語句
  9. fetch - 從結果集中取出一行
  10. fetchAll - 從結構集中取出一個包含了全部行的數組
  11. fetchColumn - 返回結果集中某一列中的數據
  12. getAttribute - 返回一個 PDOStatement 屬性
  13. getColumnMeta - 返回結果集中某一列的結構(metadata?)
  14. nextRowset - 返回下一結果集
  15. rowCount - 返回SQL語句執行後影響的行數
  16. setAttribute - 設置一個PDOStatement屬性
  17. setFetchMode - 爲 PDOStatement 設定獲取數據的方式

3、PDOException
返回PDO觸發的錯誤。你不能從你的代碼中拋出一個PDOException異常。

Php代碼   收藏代碼
  1. <?php    
  2. try {    
  3.   $dbh  =  new  PDO( 'mysql:host=localhost;dbname=test' ,  $user ,  $pass );    
  4.   foreach  ( $dbh ->query( 'SELECT * from FOO' )  as   $row ) {    
  5.     print_r($row );    
  6.   }    
  7.   $dbh  = null;    
  8. } catch (PDOException $e ) {    
  9.   print "Error!: "  .  $e ->getMessage() .  "<br/>" ;    
  10.   die ();    
  11. }    
  12. ?>  
 


錯誤處理

爲適合你的應用開發,PDO 提供了3中不一樣的錯誤處理策略。

  1. PDO::ERRMODE_SILENT

    這是默認使用的模式。PDO會在statement和database對象上設定簡單的錯誤代號,你可使用PDO->errorCode()PDO->errorInfo() 方法檢查錯誤;若是錯誤是在對statement對象進行調用時致使的,你就能夠在那個對象上使用 PDOStatement->errorCode()PDOStatement->errorInfo() 方法取得錯誤信息。而若是錯誤是在對database對象調用時致使的,你就應該在這個database對象上調用那兩個方法。

     

  2. PDO::ERRMODE_WARNING

     做爲設置錯誤代號的附加,PDO將會發出一個傳統的E_WARNING信息。這種設置在除錯和調試時是頗有用的,若是你只是想看看發生了什麼問題而不想中斷程序的流程的話。

  3. PDO::ERRMODE_EXCEPTION

    做 爲設置錯誤代號的附件,PDO會拋出一個PDOException異常並設置它的屬性來反映錯誤代號和錯誤信息。這中設置在除錯時也是頗有用的, 由於他會有效的「放大(blow up)」腳本中的出錯點,很是快速的指向一個你代碼中可能出錯區域。(記住:若是異常致使腳本中斷,事務處理回自動回滾。)

    異常模式也是很是有用的,由於你可使用比之前那種使用傳統的PHP風格的錯誤處理結構更清晰的結構處理錯誤,比使用安靜模式使用更少的代碼及嵌套,也可以更加明確地檢查每一個數據庫訪問的返回值。

    關於PHP中異常的更多信息請看Exceptions章節

PDO 使用基於SQL-92 SQLSTATE 的錯誤代號字符串;特定的PDO驅動應當將本身自己的代號對應到適當的SQLSTATE代號上。PDO->errorCode() 方法只返回單一的SQLSTATE代號。若是你須要關於一個錯誤的更加有針對性的信息,PDO也提供了一個PDO->errorInfo() 方法,它能夠返回一個包含了SQLSTATE代號,特定數據庫驅動的錯誤代號和特定數據庫驅動的錯誤說明字符串。

事務

如今你已經經過PDO創建了鏈接,在部署查詢以前你必須搞明白PDO是怎樣管理事務的。若是你之前從未遇到過事務處理,(如今簡單介紹一下:)它們提供了4個主要的特性:原子性 一致性獨立性持久性 (Atomicity, Consistency, Isolation and Durability,ACID)通俗一點講,一個事務中全部的工做在提交時,即便它是分階段執行的,也要保證安全地應用於數據庫,不被其餘的鏈接干擾。 事務工做也能夠在請求發生錯誤時輕鬆地自動取消。

事務的典型運用就是經過把批量的改變「保存起來」而後當即執行。這樣就會有完全地提升更新效率的好處。換句話說,事務可使你的腳本更快速同時可能更健壯(要實現這個優勢你仍然須要正確的使用它們)。

 

不 幸運的是,並非每一個數據庫都支持事務,所以PDO須要在創建鏈接時運行在被認爲是「自動提交」的模式下。自動提交模式意味着你執行的每一個查詢都 有它本身隱含的事務處理,不管數據庫支持事務仍是因數據庫不支持而不存在事務。若是你須要一個事務,你必須使用 PDO->beginTransaction() 方法建立一個。若是底層驅動不支持事務處理,一個PDOException就會被拋出(與你的異常處理設置無關,由於這老是一個嚴重的錯誤狀態)。在一個 事物中,你可使用 PDO->commit() 或 PDO->rollBack() 結束它,這取決於事務中代碼運行是否成功。

當腳本結束時或一個鏈接要關閉時,若是你還有一個未處理完的事務,PDO將會自動將其回滾。這是對於腳本意外終止的狀況來講是一個安全的方案——若是你沒有明確地提交事務,它將會假設發生了一些錯誤,爲了你數據的安全,因此就執行回滾了。

警告
自動回滾僅發生於你經過 PDO->beginTransaction() 創建的事務。若是你用手動方式執行了一個開始事務的查詢,PDO就沒法知道它的狀況,這樣在倒黴的事情發生時它將沒法回滾。

 
 
  在下面的例子中,讓咱們假設咱們正在建立一個新員工的一系列資 料,他被指定了一個 23 的ID,同時做爲他的基本數據,咱們也須要記錄他的薪水。執行兩個分開的更新操做很是簡單,但經過使 用 PDO->beginTransaction() 和 PDO->commit() 圍繞後調用,咱們就能夠保證在兩個操做完成以前任何 人都沒法看到這些改變。若是發生了什麼錯誤,catch塊就會將從事務開始後執行的全部改變回滾,而後打印一條錯誤信息。
Php代碼   收藏代碼
  1. try {  
  2.   $dbh  =  new  PDO( 'odbc:SAMPLE' ,  'db2inst1' ,  'ibmdb2' ,  
  3.   array (PDO::ATTR_PERSISTENT => true));  
  4.   echo   "Connected\n" ;  
  5.   $dbh ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
  6.   $dbh ->beginTransaction();  
  7.   $dbh -> exec ( "insert into staff (id, first, last) values(23, 'Joe', 'Bloggs')" );  
  8.   $dbh -> exec ("insert into salarychange (id, amount, changedate)  
  9.     values (23, 50000, NOW())");  
  10.   $dbh ->commit();  
  11. } catch (Exception  $e ) {  
  12.   $dbh ->rollBack();  
  13.   echo   "Failed: "  .  $e ->getMessage();  
  14. }  
 
數據庫鏈接

事務中執行的更新數並不受限;你能夠執行復雜查詢獲取數據,若是可能的話也能夠用獲取的數據構建更多的更新和查詢;當事務處於激活狀態時,你將被保證在你 (操做數據庫的)工做中沒有人能夠執行其餘的改變。事實上,這也不是100%正確,但若是你從未據說過事務處理,這已是一個足夠好的介紹了。

鏈接是經過實例化PDO基類創建的。對創建鏈接來講,你使用哪一個數據庫驅動並無關係,你只管用PDO這個類名就好了。PDO類的構造器接受一個能夠指定數據源(DNS)的參數和可選的數據庫用戶名、密碼參數。

例1:鏈接到MySQL:

  1. $dbh  =  new  PDO( 'mysql:host=localhost;dbname=test' ,  $user ,  $pass );

若是發生了錯誤,一個PDOException異常對象將被拋出。若是你想處理這個錯誤,你應該捕獲這個異常,或者你也能夠選擇將它交給一個經過set_exception_handler()設置的應用程序全局異常處理器。

例2:鏈接錯誤處理

Php代碼   收藏代碼
  1. try {  
  2.   $dbh  =  new  PDO( 'mysql:host=localhost;dbname=test' ,  $user ,  $pass );  
  3.   foreach  ( $dbh ->query( 'SELECT * from FOO' )  as   $row ) {  
  4.     print_r( $row );  
  5.   }  
  6.   $dbh  = null;  
  7. } catch (PDOException  $e ) {  
  8.   print  "Error!: "  .  $e ->getMessage() .  "" ;  
  9.   die ();  
  10. }   
 

警告:
若是你的應用程序沒有捕獲從PDO構造器中拋出的異 常,Zend引擎就會作出響應終端腳本的執行並顯示一條跟蹤信息。這條跟蹤信息有可能會暴露完整的數據庫鏈接信息,包括用戶名和密碼。捕獲這個異常是你的 職責,不管是明確捕獲(經過一個catch語句)仍是經過set_exception_handler()隱含捕獲。

成 功創建數據庫鏈接以後,一個PDO類的實例就返回到了你的腳本中。鏈接在PDO對象的生存期內會一直保持活動狀態。要關閉這個鏈接,你須要經過刪 除全部指向它的引用來銷燬這個對象。你能夠經過向指向這個對象的變量賦一個NULL值作到這一點。若是你沒有明確地這樣作,PHP會在腳本結束時自動關閉 這個鏈接。

Php代碼   收藏代碼
  1. //關閉鏈接:  
  2. $dbh  =  new  PDO( 'mysql:host=localhost;dbname=test' ,  $user ,  $pass );  
  3. // use the connection here  
  4. // do something.  
  5. // and now we're done; close it  
  6. $dbh  = null;  
 
許 多Web應用會由於使用了向數據庫的持久鏈接而獲得優化。持久鏈接不會在腳本結束時關閉,相反它會被緩存起 來並在另外一個腳本經過一樣的標識請求一個鏈接時得以從新利用。持久鏈接的緩存可使你避免在腳本每次須要與數據庫對話時都要部署一個新的鏈接的資源消耗, 讓你的Web應用更加快速。

 


Php代碼   收藏代碼
  1. //持久鏈接  
  2. $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass,  
  3.  array(    PDO::ATTR_PERSISTENT => true;));  
 
相關文章
相關標籤/搜索