程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP開發筆記系列(一)-PDO使用

PHP開發筆記系列(一)-PDO使用

編輯:關於PHP編程

    之前一段時間,開始了php的研究,看了關於PDO的一些資料,發現不錯,整理和總結一下,作為開發筆記,留待日後使用,《PHP開發筆記系列(一)-PDO使用》。 

    PDO是PHP Data Objects的簡稱,是一種數據庫訪問抽象層。PDO是用於多種數據庫的一致接口。類比的說,PDO做的事情類似於JAVA中的持久層框架(Hibernate、OpenJPA)的功能,為異構數據庫提供一個統一的編程接口,這樣就不必再使用mysql_*、pg_*這樣的函數,也不必再寫自己的"GenericDAO"了。PDO在PHP5.1的時候一起發布,所以我們用的PHP5.2、PHP5.3都已經可以使用。 

    為了方便,我們使用MySQL5來做演示。 

0. 建立實驗環境數據庫及相關表 

Sql代碼  收藏代碼
  1. CREATE TABLE `blog` (  
  2.   `id` int(10) NOT NULL AUTO_INCREMENT,  
  3.   `title` varchar(255) NOT NULL,  
  4.   PRIMARY KEY (`id`)  
  5. ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1  



1. 使用PDO訪問數據庫 
    通過PDO訪問數據庫的步驟是:a)指定dsn、username、password,b)通過#a中的設置構造PDO對象,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-access.php  
  2. url:http://localhost:88/pdo/pdo-access.php  
  3. <?php  
  4.     // 設置dsn、username、passwd  
  5.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     // 構造PDO對象  
  10.     try {  
  11.         $dbh = new PDO($dsn, $username, $passwd);  
  12.         echo 'connect to database successfully!';  
  13.     } catch (Exception $e) {  
  14.         echo 'Fail to connect to database!\n';  
  15.         echo $e->getMessage();  
  16.     }  
  17. ?>  



    備注:DSN即Data Source Name-數據源名稱,提供數據庫的連接信息,包括三部分,PDO驅動名稱(MySQL、SQLite、PostgreSQL等)、冒號和驅動特定的語法。但是一般情況下,我們都很難記住這些,可以下載個php manual查,也可以到php的官網查。 

2. 使用Query方法查詢數據 
    在#1的基礎上,連接數據庫成功後,構造SQL語句,調用query方法返回結構數組,通過foreach進行數據結果遍歷,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-query.php  
  2. url:http://localhost:88/pdo/pdo-query.php?title=title1  
  3. <?php  
  4.   
  5.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     try {  
  10.         $dbh = new PDO($dsn, $username, $passwd);  
  11.         echo 'connect to database successfully!'."\r\n";  
  12.       
  13.         $title = 'title1';  
  14.         // 構造SQL語句  
  15.         $sql = "SELECT * FROM blog WHERE title = '".$title."'";  
  16.         // 執行查詢並遍歷結果  
  17.         foreach ($dbh->query($sql) as $row){  
  18.             print $row['id']."\t";  
  19.             print $row['title']."\t";  
  20.         }  
  21.     } catch (PDOException $e) {  
  22.         echo 'Errors occur when query data!\n';  
  23.         echo $e->getMessage();  
  24.     }  
  25. ?>  



    備注:一般情況下, 通過構造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遍歷結果集。代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-fetch.php  
  2. url:http://localhost:88/pdo/pdo-prepare-fetch.php?title=title1  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.     $username = 'root';  
  6.     $passwd = 'password';  
  7.       
  8.     // 從請求獲取title參數值  
  9.     $title = $_GET['title'];  
  10.     try {  
  11.         $dbh = new PDO($dsn, $username, $passwd);  
  12.         echo 'connect to database successfully!'."<br/>";  
  13.       
  14.         // 構造SQL語句,使用綁定變量  
  15.         $sql = "SELECT * FROM blog WHERE title = :title";  
  16.         // 編譯SQL  
  17.         $stmt = $dbh->prepare($sql);  
  18.         // 為綁定變量賦值  
  19.         $stmt->bindParam(":title", $title, PDO::PARAM_STR);  
  20.         // 執行SQL  
  21.         $stmt->execute();  
  22.         // 以聯合數組方式獲取結果,並遍歷結果  
  23.         while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {  
  24.             print $row['id']."\t";  
  25.             print $row['title']."\t";  
  26.         }  
  27.     } catch (PDOException $e) {  
  28.         echo 'Errors occur when query data!\n';  
  29.         echo $e->getMessage();  
  30.     }  
  31. ?>  



    除了使用上面的PDO::FETCH_ASSOC返回聯合數組外,還可以使用fetchObject方法,返回結果集對象,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-fetch-object.php  
  2. url:http://localhost:88/pdo/pdo-prepare-fetch-object.php?title=title1  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.     $username = 'root';  
  6.     $passwd = 'password';  
  7.       
  8.     $title = $_GET['title'];  
  9.     try {  
  10.         $dbh = new PDO($dsn, $username, $passwd);  
  11.         echo 'connect to database successfully!'."<br/>";  
  12.       
  13.         $sql = "SELECT * FROM blog WHERE title = :title";  
  14.         $stmt = $dbh->prepare($sql);  
  15.         $stmt->bindParam(":title", $title, PDO::PARAM_STR);  
  16.         $stmt->execute();  
  17.         // 以對象數組方式獲取結果,並遍歷結果       
  18.         while ($row = $stmt->fetchObject()) {  
  19.             print $row->id."\t";  
  20.             print $row->title."\t";  
  21.         }  
  22.     } catch (Exception $e) {  
  23.         echo 'Errors occur when query data!\n';  
  24.         echo $e->getMessage();  
  25.     }  
  26. ?>  



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); 

Php代碼  收藏代碼
  1. <?php  
  2.     ...  
  3.     try {  
  4.         ...  
  5.     } catch (Exception $e) {  
  6.         echo 'Errors occur when operation!'."<br/>";  
  7.         // 獲取Exception信息  
  8.         echo $e->getMessage()."<br/>";  
  9.         // 獲取錯誤碼  
  10.         echo $e->getCode()."<br/>";  
  11.         // 獲取出錯文件名  
  12.         echo $e->getFile()."<br/>";  
  13.         // 獲取出錯行  
  14.         echo $e->getLine()."<br/>";  
  15.         // 把異常以字符串返回  
  16.         echo $e->getTraceAsString();  
  17.     }  
  18. ?>  



5. 使用prepare和execute方法插入/更新數據 
    方法和#3中進行查詢的差不多,只是構造的SQL語句是insert語句或update語句,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-insert.php  
  2. url:http://localhost:88/pdo/pdo-insert.php?title=title11  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.       
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     $title = $_GET['title'];  
  10.     try {  
  11.         $dbh = new PDO($dsn, $username, $passwd);  
  12.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
  13.         echo 'connect to database successfully!'."<br/>";  
  14.       
  15.         // 構造Insert語句  
  16.         $sql = "INSERT INTO blog(title) VALUES(:title)";  
  17.         $stmt = $dbh->prepare($sql);  
  18.         $stmt->bindParam(":title", $title);  
  19.         $stmt->execute();  
  20.     } catch (Exception $e) {  
  21.         echo 'Errors occur when query data!\n';  
  22.         echo $e->getMessage();  
  23.     }  
  24. ?>  



Php代碼  收藏代碼
  1. file:pdo-prepare-update.php  
  2. url:http://localhost:88/pdo/pdo-update.php?id=1&title=title12  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.       
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     $id = $_GET['id'];  
  10.     $title = $_GET['title'];  
  11.     try {  
  12.         $dbh = new PDO($dsn, $username, $passwd);  
  13.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
  14.         echo 'connect to database successfully!'."<br/>";  
  15.       
  16.         // 構造update語句  
  17.         $sql = "UPDATE blog SET title=:title where id=:id";  
  18.         $stmt = $dbh->prepare($sql);  
  19.         $stmt->bindParam(":id", $id);  
  20.         $stmt->bindParam(":title", $title);  
  21.         $stmt->execute();  
  22.     } catch (Exception $e) {  
  23.         echo 'Errors occur when query data!\n';  
  24.         echo $e->getMessage();  
  25.     }  
  26. ?>  



6. 獲取返回的行數 
    使用#3中的prepare和execute方法,然後將sql語句改成count的,例如SELECT COUNT(id) FROM article ...,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-fetch-column.php  
  2. url:http://localhost:88/pdo/pdo-prepare-fetch-column.php?id=1&title=title12  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.     $username = 'root';  
  6.     $passwd = 'password';  
  7.       
  8.     try {  
  9.         $dbh = new PDO($dsn, $username, $passwd);  
  10.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);  
  11.         echo 'connect to database successfully!'."<br/>";  
  12.       
  13.         // 構造count語句  
  14.         $sql = "SELECT COUNT(id) FROM blog";  
  15.         $stmt = $dbh->prepare($sql);  
  16.         $stmt->execute();  
  17.         // 使用fetchColumn獲取0列值  
  18.         echo $stmt->fetchColumn()." rows returned!";  
  19.     } catch (Exception $e) {  
  20.         echo 'Errors occur when query data!\n';  
  21.         echo $e->getMessage();  
  22.     }  
  23. ?>  



7. 獲取受影響的行數 
    使用#3中的prepare和execute方法,然後將SQL語句改成insert、update、delete語句即可,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-row-count.php  
  2. url:http://localhost:88/pdo/pdo-prepare-row-count.php?id=1  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.     $username = 'root';  
  6.     $passwd = 'password';  
  7.       
  8.     $id = $_GET['id'];  
  9.     try {  
  10.         $dbh = new PDO($dsn, $username, $passwd);  
  11.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);  
  12.         echo 'connect to database successfully!'."<br/>";  
  13.       
  14.         $sql = "DELETE FROM blog WHERE id=:id";  
  15.         $stmt = $dbh->prepare($sql);  
  16.         $stmt->bindParam(":id", $id);  
  17.         $stmt->execute();  
  18.         // 獲取update、insert、delete操作後影響的行數  
  19.         echo $stmt->rowCount()." rows affected!";  
  20.     } catch (Exception $e) {  
  21.         echo 'Errors occur when data operation!\n';  
  22.         echo $e->getMessage();  
  23.     }  
  24. ?>  



8. 獲得新插入行的ID值 
    為數據庫表插入新數據行時,我們需要獲得剛剛插入的新行的ID值,此時我們需要使用到PDO的lastInsertId()方法,代碼如下: 

Php代碼  收藏代碼
  1. file:pdo-prepare-last-insertid.php  
  2. url:http://localhost:88/pdo/pdo-prepare-last-insertid.php?title=title13  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.       
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     $title = $_GET['title'];  
  10.     try {  
  11.         $dbh = new PDO($dsn, $username, $passwd);  
  12.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
  13.         echo 'connect to database successfully!'."<br/>";  
  14.       
  15.         $sql = "INSERT INTO blog(title) VALUES(:title)";  
  16.         $stmt = $dbh->prepare($sql);  
  17.         $stmt->bindParam(":title", $title);  
  18.         $stmt->execute();  
  19.         // 獲取上一個之行的insert語句插入的數據的id值  
  20.         echo $dbh->lastInsertId();  
  21.     } catch (Exception $e) {  
  22.         echo 'Errors occur when query data!\n';  
  23.         echo $e->getMessage();  
  24.     }  
  25. ?>  



9. 使用PDO進行事務管理 
    事務是進行程序開發時,保證數據ACID(可分性、一致性、獨立性、持久性)的工具。要不全部成功,要不全部不成功,這樣才能保證關聯數據的保存能夠達到預期的目的。下面使用PDO的Transaction來進行實驗,進行多比數據插入,開啟事務,第一句sql是可以正常插入,第二句sql插入出錯,檢查是否rollback。 

Php代碼  收藏代碼
  1. file:pdo-prepare-transaction.php  
  2. url:http://localhost:88/pdo/pdo-prepare-transaction.php  
  3. <?php  
  4.     $dsn = 'mysql:host=localhost;dbname=pdotest';  
  5.       
  6.     $username = 'root';  
  7.     $passwd = 'password';  
  8.       
  9.     try {  
  10.         $dbh = new PDO($dsn, $username, $passwd);  
  11.         $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
  12.         echo 'connect to database successfully!'."<br/>";  
  13.         // 開啟事務  
  14.         $dbh->beginTransaction();  
  15.         $sql = "INSERT INTO blog(title) VALUES(:title)";  
  16.         $stmt = $dbh->prepare($sql);  
  17.         $stmt->execute(array(':title'=>'insert title1'));  
  18.         $stmt->execute(array(':title'=>NULL));  
  19.         // 提交事務  
  20.         $dbh->commit();  
  21.     } catch (Exception $e) {  
  22.         echo 'Errors occur when data operation!\n';  
  23.         echo $e->getMessage();  
  24.         // 回滾事務  
  25.         $dbh->rollBack();  
  26.     }  
  27. ?>  



10. 使用PDO進行數據庫備份 
    使用system函數,將我們構造的mysqldump命令傳入即可。下面為了演示,只做了簡單的調用。 

Php代碼  收藏代碼
  1. file:pdo-backup.php  
  2. url:http://localhost:88/pdo/pdo-backup.php  
  3. <?php  
  4.     $username="root";  
  5.     $passwd="password";  
  6.     $dbname="pdotest";  
  7.     $file='d:/'.$dbname.'.sql';  
  8.     // 構造備份命令  
  9.     $cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." >".$file;  
  10.     // 執行備份命令  
  11.     system($cmd,$error);  
  12.     if($error){  
  13.         trigger_error("backup failed".$error);  
  14.     }  
  15. ?>  



    采用工廠模式: 

Php代碼  收藏代碼
  1. file:AbstractMySQLDump.php  
  2. <?php  
  3.     require_once 'MySQLDump_Win.php';  
  4.       
  5.     abstract class AbstractMySQLDump {  
  6.         protected $cmd;  
  7.           
  8.         abstract function __construct($username, $passwd, $dbname, $file);  
  9.           
  10.         // 依據操作系統類型,使用工廠方法構造備份類  
  11.         public static function factory($username, $passwd, $dbname, $file){  
  12.             if(strtoupper(substr(PHP_OS, 0, 3))==='WIN'){  
  13.                 return new MySQLDump_Win($username, $passwd, $dbname, $file);  
  14.             }else{  
  15. //              implement MySQLDump_NIX($username, $passwd, $dbname, $file);   
  16.             }  
  17.         }  
  18.           
  19.         // 備份邏輯  
  20.         public function backup(){  
  21.             system($this->cmd, $error);  
  22.             // 判斷是否出錯及出錯邏輯  
  23.             if($error){  
  24.                 trigger_error("backup failure! command:".$this->cmd." Error:".$error);  
  25.             }  
  26.         }  
  27.     }  
  28. ?>  



Php代碼  收藏代碼
  1. file:MySQLDump_Win.php  
  2. <?php  
  3.     class MySQLDump_Win extends AbstractMySQLDump {  
  4.                       
  5.         // 覆蓋父類的構造方法  
  6.         public function __construct($username, $passwd, $dbname, $file){  
  7.            $this->cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." > ".$file;  
  8.         }  
  9.     }  
  10. ?>  



Php代碼  收藏代碼
    1. file:MySQLDumpTest.php  
    2. url:http://localhost:88/pdo/MySQLDumpTest.php  
    3. <?php  
    4.     require_once 'AbstractMySQLDump.php';  
    5.       
    6.     $username = "root";  
    7.     $passwd = "password";  
    8.     $dbname = "pdotest";  
    9.     $file = "d:/".$dbname.".sql";  
    10.       
    11.     // 使用工廠方法生成備份類  
    12.     $dump = AbstractMySQLDump::factory($username, $passwd, $dbname, $file);  
    13.     // 執行備份類的backup方法  
    14.     $dump->backup();   
    15. ?>  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved