PDO(php data object)擴展類庫為php訪問數據庫定義了輕量級的、一致性的接口,它提供了一個數據庫訪問抽象層,這樣,無論使用什麼數據庫,都可以通過一致的函數執行查詢和獲取數據,大大簡化了數據庫的操作,並能夠屏蔽不同數據庫之間的差異,使用PDO可以很方便地進行跨數據庫程序的開發,以及不同數據庫間的移植,是將來php在數據庫處理方面的主要發展方向,它可以支持mysql、postgresql、oracle、mssql等多種數據庫
使用PDO在與不同數據庫管理系統之間交互時,PDO對象中的成員方法是統一各種數據庫的訪問接口,所以在使用PDO與數據庫進行交互之前,首先要創建一個PDO對象。在通過構造方法創建對象的同時,需要建立一個與數據庫服務器的連接,並選擇一個數據庫
PDO的構造方法原型如下
__construct ( string $dsn [,string $username [,string $password [,array $driver_options ]]] )
在構造方法中,第一個必選的參數是數據源名(dsn),用來定義一個確定的數據庫和必須用到的驅動程序。DSN的PDO命名慣例為PDO驅動程序的名稱,後面為一個冒號,再後面是可選的驅動程序的數據庫連接變量信息,如主機名、端口和數據庫名
構造方法中的第二個參數username和第三個參數password分別指定用於連接數據庫的用戶名和密碼。最後一個參數driver_options需要一個數組,用來指定連接所需的所有額外選項,傳遞附加的調優參數到PDO或底層驅動程序
/*連接如果失敗,使用異常處理模式進行捕獲 */ $dsn = 'mysql:dbname=pdotest;host=127.0.0.1'; //連接MySQL數據庫的DSN $user = 'root'; //MySQL數據庫的用戶名 $password = '*****'; //MySQL數據庫的密碼 try { $dbh = new PDO($dsn, $user, $password); } catch (PDOException $e) { echo '數據庫連接失敗: ' . $e->getMessage(); }
在創建PDO對象時,有一些與數據庫連接相關的選項,可以將必要的幾個選項組成數據傳遞給構造方法的第四個參數driver_opts中,用來傳遞附加的調優參數到PDO或底層驅動程序
PDO::ATTR_AUTOCOMMIT): PDO是否關閉自動提交功能 PDO::ATTR_ERRMODE): 當前PDO的錯誤處理的模式 PDO::ATTR_CASE): 表字段字符的大小寫轉: PDO::ATTR_CONNECTION_STATUS): 與連接狀態相關特有信息: PDO::ATTR_ORACLE_NULLS): 空字符串轉換為SQL的null PDO::ATTR_PERSISTENT): 應用程序提前獲取數據大 PDO::ATTR_SERVER_INFO): 與數據庫特有的服務器信 PDO::ATTR_SERVER_VERSION): 數據庫服務器版本號信息 PDO::ATTR_CLIENT_VERSION): 數據庫客戶端版本號信息
//設置持久連接的選項數組作為最後一個參數,可以一起設置多個元素 $opt = array(PDO::ATTR_PERSISTENT => true); try { $db = new PDO('mysql:dbname=pdotest;host=127.0.0.1','root','*****',$opt); } catch (PDOException $e) { echo "數據庫連接失敗: " .$e->getMessage(); }
調整PDO的行為屬性
在PDO對象中有很多屬性用來調整PDO的行為或獲取底層驅動程序狀態。如果在創建PDO對象時,沒有在構造方法中最後一個參數過屬性選項,也可以在對象創建完成之後,通過PDO對象中的setAttribute()和getAttribute()方法設置和獲取這些屬性的值
PDO::getAttribute()
PDO::getAttribute()用於取回一個數據庫連接的屬性
mixed PDO::getAttribute ( int $attribute )
PDO::setAttribute()
PDO::setAttribute()用於設置屬性
bool PDO::setAttribute ( int $attribute , mixed $value )
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //$dbh->setAttribute(3,2); $dbh->setAttribute(PDO::ATTR_AUTOCOMMIT,0);//$dbh->setAttribute(0,0); $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); //$dbh->setAttribute(19,2); echo "\nPDO是否關閉自動提交功能:". $dbh->getAttribute(PDO::ATTR_AUTOCOMMIT); echo "\n當前PDO的錯誤處理的模式:". $dbh->getAttribute(PDO::ATTR_ERRMODE); echo "\n表字段字符的大小寫轉換: ". $dbh->getAttribute(PDO::ATTR_CASE); echo "\n與連接狀態相關特有信息: ". $dbh->getAttribute(PDO::ATTR_CONNECTION_STATUS); echo "\n空字符串轉換為SQL的null:". $dbh->getAttribute(PDO::ATTR_ORACLE_NULLS); echo "\n應用程序提前獲取數據大小:".$dbh->getAttribute(PDO::ATTR_PERSISTENT); echo "\n與數據庫特有的服務器信息:".$dbh->getAttribute(PDO::ATTR_SERVER_INFO); echo "\n數據庫服務器版本號信息:". $dbh->getAttribute(PDO::ATTR_SERVER_VERSION); echo "\n數據庫客戶端版本號信息:". $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION);
錯誤處理
PDO一共提供了三種不同的錯誤處理模式,不僅可以滿足不同風格的編程,也可以調整擴展處理錯誤的方式
PDO:ERRORMODE_SILENT
這是默認模式,在錯誤發生時不進行任何操作,PDO將只設置錯誤代碼。開發人員可以通過PDO對象中的errorCode()和errorInfo()方法對語句和數據庫對象進行檢查。如果錯誤是由於對語句對象的調用而產生的,那麼可以在那個語句對象上調用errorCode()或errorInfo()方法。如果錯誤是由於調用數據庫對象而產生的,那麼可以在那個數據庫對象上調用上述兩個方法
PDO:ERRMODE_WARNING
除了設置錯誤代碼以外,PDO還將發出一條PHP傳統的E_WARNING消息,可以使用常規的PHP錯誤處理程序捕獲該警告。如果只是想看看發生了什麼問題,而無意中斷應用程序的流程,那麼在調試或測試中這種設置很有用
$dbh->setAttrbute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);//設置警告模式處理錯誤
PDO:ERRMODE_EXCEPTION
除了設置錯誤代碼以外,PDO還將拋出一個PDOException,並設置其屬性,以反映錯誤代碼和錯誤信息。這種設置在調試中也很有用,因為它會放大腳本中產生錯誤的地方,從而可以非常快速地指出代碼中有問題的潛在區域。異常模式另一個有用的地方是,與傳統的PHP風格的警告相比,可以更清晰地構造自己的錯誤處理,而且,比起以寂靜方式及顯式檢查每個數據庫調用的返回值,異常模式代碼及嵌套代碼也更少
$dbh->setAttrbute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);//設置異常模式處理錯誤
執行SQL語句
在使用PDO執行查詢數據之前,先提供一組相關的數據。創建PDO對象並通過mysql驅動連接mysql數據庫服務器,創建一個以'testdb'命名的數據庫,並在該數據庫中創建一個聯系人信息表contactInfo
CREATE TABLE contactInfo( uid MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, departmentID CHAR(3) NOT NULL, address VARCHAR(80) NOT NULL, phone VARCHAR(20), email VARCHAR(20), PRIMARY KEY(uid) );
數據表contactInfo建立之後,向表中插入多行記錄
INSERT INTO contactInfo(name,departmentID,address,phone,email) VALUES ('張三','D01','朝陽','15011111234','[email protected]'),('李四','D02','朝陽','15011112345','[email protected]'),('王五','D02','海澱','15011113456','[email protected]'),('趙四','D01','海澱','15011114567','[email protected]');
PDO::exec()
PDO::exec()函數執行一條SQL語句,並返回受影響的行數
int PDO::exec ( string $statement )
當執行INSERT、UPDATE、DELETET等沒有結果集的查詢時,使用PDO對象中的exec()方法去執行。該方法成功執行後,將返回受影響的行數
<?php try { //創建對象 $dbh = new PDO("mysql:host=localhost;dbname=testdb", "root", "zhiaihebe0123"); }catch(PDOException $e) { echo "數據庫連接失敗:".$e->getMessage(); exit; } $query = "UPDATE contactInfo SET phone='12345678900' WHERE name='張三'"; $affected = $dbh->exec($query); if($affected){ //數據表contactInfo中受影響的行數為:1 echo '數據表contactInfo中受影響的行數為:' .$affected; }else{ print_r($dbh->errorInfo()); } $query = "UPDATE contactInfo SET phone='123456789' WHERE (uid%2 = 0)"; $affected = $dbh->exec($query); if($affected){ //數據表contactInfo中受影響的行數為:2 echo '數據表contactInfo中受影響的行數為:' .$affected; }else{ print_r($dbh->errorInfo()); } ?>
PDO::lastInsertId()
PDO::lastInsertId()函數用於返回最後插入行的ID或序列值
string PDO::lastInsertId ([ string $name = NULL ] )
<?php try { //創建對象 $dbh = new PDO("mysql:host=localhost;dbname=testdb", "root", "zhiaihebe0123"); }catch(PDOException $e) { echo "數據庫連接失敗:".$e->getMessage(); exit; } try{ $query = "INSERT INTO contactInfo(name,departmentID,phone,email) VALUES ('諸葛','D03','120120120','[email protected]')"; $affected = $dbh->exec($query); echo $affected."<br>";//1 echo $dbh->lastInsertId();//5 }catch(PDOException $e){ echo "錯誤:" .$e->getMessage(); } ?>
PDO::query()
當執行返回結果集的SELECT查詢時,或者所影響的行數無關緊要時,應當使用PDO對象中的query()方法。如果該方法成功執行指定的查詢,則返回一個PDOStatement對象。如果使用了query()方法,並想了解獲取的數據行總數,可以使用PDOStatement對象中的rowCount()方法獲取
PDOStatement::rowCount()
PDOStatement::rowCount()函數返回受上一個 SQL 語句影響的行數
int PDOStatement::rowCount ( void )
<?php try { //創建對象 $dbh = new PDO("mysql:host=localhost;dbname=testdb", "root", "zhiaihebe0123"); }catch(PDOException $e) { echo "數據庫連接失敗:".$e->getMessage(); exit; } $query = "SELECT name,phone,email FROM contactInfo WHERE departmentId='D01'"; try{ $pdostatement = $dbh->query($query); echo "一共從表中獲取到".$pdostatement->rowCount()."條記錄:<br>"; foreach($pdostatement as $row){ echo $row['name'] ."\t"; echo $row['phone'] ."\t"; echo $row['email'] ."<br>"; } }catch (PDOException $e){ echo $e->getMessage(); } ?>
事務是確保數據庫一致的機制,是一個或一系列的查詢,作為一個單元的一組有序的數據庫操作。如果組中的所有SQL語句都操作成功,則認為事務成功,事務則被提交,其修改將作用於所有其他數據庫進程。即使在事務的組中只有一個環節操作失敗,事務也不成功,則整個事務將被回滾,該事務中所有操作都被取消。事務功能是企業級數據庫的一個重要部分,因為很多業務過程都包括多個步驟。如果任何一個步驟失敗,則所有步驟都不應發生。事務處理有4個特征:原子性(Atomicity)、一致性(Consistency)、獨立性(Isolation)和持久性(Durability),即ACID。對於在一個事務中執行的任何工作,即使它是分階段進行的,也一定可以保證該工作會安全地應用於數據庫,並且在工作被提交時,不會受到其他連接的影響
MySQL目前只有InnoDB和BDB兩個數據庫表類型才支持事務,兩個表類型具有相同的特性,InnoDB表類型具有比BDB還豐富的特性,速度更快,因此建議使用InnoDB表類型。創建InnoDB類型的表實際上與創建任何其他類型表的過程沒有區別,如果數據庫沒有設置為默認的表類型,只要在創建時顯式指定要將表創建為InnoDB類型
要實現事務處理,首先要使用InnoDB引擎
ALTER TABLE contactInfo engine=innodb;
在默認的情況下,MySQL是以自動提交(autocommit)模式運行的,這就意味著所執行的每一個語句都將立即寫入數據庫中。但如果使用事務安全的表格類型,是不希望有自動 提交的行為的,所以要在當前的會話中關閉自動提交
SET AUTOCOMMIT = 0;//在當前的會話中關閉自動提交
如果提交被打開了,必須開啟一個事務;如果自動提交是關閉的,則不需要使用這條命令,因為輸入一個SQL命令時,一個事務將自動啟動
START TRANSACTION;//開啟一個事務
在完成了一組事務的語句輸入後,需要提交一個事務,該事務才能在其他會話中被其他用戶所見
COMMIT;//提交一個事務給數據庫
如果改變注意,可以回滾到以前的狀態
ROOLBACK;//事務被回滾,所有操作都被取消
事務處理完成後,再次開啟自動提交
SET AUTOCOMMIT = 1;
下面在PHP中進行事務處理操作,對張三和李四進行部門交換來輪崗培養
<?php try { //創建對象 $dbh = new PDO("mysql:host=localhost;dbname=testdb", "root", "zhiaihebe0123"); //設置錯誤使用異常的模式 $dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //關閉自動提交 $dbh-> setAttribute(PDO::ATTR_AUTOCOMMIT, 0); }catch(PDOException $e) { echo "數據庫連接失敗:".$e->getMessage(); exit; } try { //開啟一個事務 $dbh -> beginTransaction(); $affected_rows = $dbh->exec("UPDATE contactInfo set departmentID = 'D02' where uid=1"); if($affected_rows > 0) { echo "張三轉崗成功!<br>"; } else { throw new PDOException("張三轉崗失敗!<br>"); } $affected_rows = $dbh-> exec("UPDATE contactInfo set departmentID = 'D01' where uid=2"); if($affected_rows) { echo "李四轉崗成功!<br>"; }else { throw new PDOException("李四轉崗失敗!<br>"); } echo "輪崗成功!<br>"; //提交以上的操作 $dbh->commit(); }catch(PDOException $e) { echo "錯誤:".$e->getMessage(); echo "轉崗失敗!<br>"; //撤銷所有操作 $dbh -> rollback(); } //運行完成以後, 最後開啟自動提交 $dbh-> setAttribute(PDO::ATTR_AUTOCOMMIT, 1); ?>