最近在linux裝了新的環境,php5.6+mysql5.5+nginx。然後用原來的mysql鏈接數據庫出現的錯誤。
原因就是說連接數據庫的方法太舊。建議我用mysqli和PDO來連接數據庫。
好吧,咱也不能落後,使用mysqli的確也簡單了不少,但是PDO貌似更簡單。效率也會得到提升。根據官方文檔,貌似對於sql注入的一些風險也做了屏蔽。所以今天寫的 博客就是關於php用PDO連接mysql的一些介紹啦!
PDO是PHP 5新加入的一個重大功能,因為在PHP 5以前的php4/php3都是一堆的數據庫擴展來跟各個數據庫的連接和處理,什麼php_mysql.dll、php_pgsql.dll、php_mssql.dll、php_sqlite.dll等等擴展來連接MySQL、PostgreSQL、MS SQL Server、SQLite,同樣的,我們必須借助 ADOdb、PEAR::DB、PHPlib::DB之類的數據庫抽象類來幫助我們,無比煩瑣和低效,畢竟,php代碼的效率怎麼能夠我們直接用C/C++寫的擴展效率高捏?所以嘛,PDO的出現是必然的,大家要平靜學習的心態去接受使用,也許你會發現能夠減少你不少功夫哦。
PDO 是 PHP 5.1 發行的,也就是說,在 5.1 之前的版本是不支持 PDO,5.1之後的都支持啦。在PHP5.0的PECL擴展中也可以使用。
PDO如何使用:
這裡我們就以PHP的黃金搭檔mysql作為例子看看:
PDO_MYSQL:PDO_MYSQL是PDO接口能夠完成連接mysql數據庫的驅動(注:僅使用於mysql 3.x以上版本)。
安裝:打開php.ini文件,可以找到如下代碼,這裡可以看到mysql的驅動默認已經打開(前面沒有用於注釋的分號),如有連接其他數據庫的需要,自行添加其他數據庫的驅動程序(取出相應的項前面的分號,沒有的添上)。
//各數據庫的PDO驅動 extension=php_pdo.dll extension=php_pdo_firebird.dll //Firebird extension=php_pdo_informix.dll //Informix extension=php_pdo_mssql.dll //sql server extension=php_pdo_mysql.dll //mysql extension=php_pdo_oci.dll //Oracle extension=php_pdo_oci8.dll extension=php_pdo_odbc.dll //DB2 extension=php_pdo_pgsql.dll //PostgreSQL extension=php_pdo_sqlite.dll //SQLite連接:通過創建PDO基類的實例創建連接。
//連接到數據庫 $db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
<?php header('content-type:text/html;charset=utf-8'); try { $db = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', ''); //查詢 $rows = $db->query('SELECT * from members')->fetchAll(PDO::FETCH_ASSOC); $rs = array(); foreach($rows as $row) { $rs[] = $row; } $db = null; } catch (PDOException $e) { print "Error!: " . $e->getMessage() . "<br/>"; die(); } print_r($rs); ?>
不明白啥意思,俺們來慢慢講講。這行:
$dsn = "mysql:host=127.0.0.1;dbname=test";
就是構造我們的DSN(數據源),看看裡面的信息包括:數據庫類型是mysql,主機地址是localhost,數據庫名稱是test,就這麼幾個信息。不同數據庫的數據源構造方式是不一樣的。
$db = new PDO($dsn, 'root', '');
初始化一個PDO對象,構造函數的參數第一個就是我們的數據源,第二個是連接數據庫服務器的用戶,第三個參數是密碼。我們不能保證連接成功,後面我們會講到異常情況,這裡我們姑且認為它是連接成功的。
$count = $db->exec("INSERT INTO foo SET name = 'heiyeluren',gender='男',time=NOW()");
echo $count;
調用我們連接成功的PDO對象來執行一個查詢,這個查詢是一個插入一條記錄的操作,使用PDO::exec() 方法會返回一個影響記錄的結果,所以我們輸出這個結果。最後還是需要結束對象資源:
$db = null;
默認這個不是長連接,如果需要數據庫長連接,需要最後加一個參數:array(PDO::ATTR_PERSISTENT => true)變成這樣:
$db = new PDO($dsn, 'root', '', array(PDO::ATTR_PERSISTENT => true));
一次操作就這麼簡單,也許跟以前的沒有太大區別,跟ADOdb倒是有幾分相似。
使用setFetchMode方法來設置獲取結果集的返回值的類型,同樣類型還有:PDO::FETCH_OBJ -- 按照對象的形式,類似於以前的 mysql_fetch_object()
$db->query($sql); 當$sql 中變量可以用$dbh->quote($params); //轉義字符串的數據
PDOStatement::bindColumn — 綁定一列到一個 PHP 變量 PDOStatement::bindParam — 綁定一個參數到指定的變量名 PDOStatement::bindValue — 把一個值綁定到一個參數 PDOStatement::closeCursor — 關閉游標,使語句能再次被執行。 PDOStatement::columnCount — 返回結果集中的列數 PDOStatement::debugDumpParams — 打印一條 SQL 預處理命令 PDOStatement::errorCode — 獲取跟上一次語句句柄操作相關的 SQLSTATE PDOStatement::errorInfo — 獲取跟上一次語句句柄操作相關的擴展錯誤信息 PDOStatement::execute — 執行一條預處理語句 PDOStatement::fetch — 從結果集中獲取下一行 PDOStatement::fetchAll — 返回一個包含結果集中所有行的數組 PDOStatement::fetchColumn — 從結果集中的下一行返回單獨的一列。 PDOStatement::fetchObject — 獲取下一行並作為一個對象返回。 PDOStatement::getAttribute — 檢索一個語句屬性 PDOStatement::getColumnMeta — 返回結果集中一列的元數據 PDOStatement::nextRowset — 在一個多行集語句句柄中推進到下一個行集 PDOStatement::rowCount — 返回受上一個 SQL 語句影響的行數 PDOStatement::setAttribute — 設置一個語句屬性 PDOStatement::setFetchMode — 為語句設置默認的獲取模式。
$db->exec("DELETE FROM `xxxx_menu` where mid=43");
PDO->beginTransaction(),PDO->commit(),PDO->rollBack()這三個方法是在支持回滾功能時一起使用的。PDO->beginTransaction()方法標明起始點,PDO->commit()方法標明回滾結束點,並執行SQL,PDO->rollBack()執行回滾。
<?php try { $dbh = new PDO('mysql:host=localhost;dbname=test', ‘root', ”); $dbh->query('set names utf8;'); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->beginTransaction(); $dbh->exec(”INSERT INTO `test`.`table` (`name` ,`age`)VALUES ('mick', 22);”); $dbh->exec(”INSERT INTO `test`.`table` (`name` ,`age`)VALUES ('lily', 29);”); $dbh->exec(”INSERT INTO `test`.`table` (`name` ,`age`)VALUES ('susan', 21);”); $dbh->commit(); } catch (Exception $e) { $dbh->rollBack(); echo “Failed: ” . $e->getMessage(); } ?>現在你已經通過PDO建立了連接,在部署查詢之前你必須搞明白PDO是怎樣管理事務的。如果你以前從未遇到過事務處理,(現在簡單介紹一下:)它們提供了4個主要的特性:原子性,一致性,獨立性和持久性(Atomicity, Consistency, Isolation and Durability,ACID)通俗一點講,一個事務中所有的工作在提交時,即使它是分階段執行的,也要保證安全地應用於數據庫,不被其他的連接干擾。事務工作也可以在請求發生錯誤時輕松地自動取消。
事務的典型運用就是通過把批量的改變“保存起來”然後立即執行。這樣就會有徹底地提高更新效率的好處。換句話說,事務可以使你的腳本更快速同時可能更健壯(要實現這個優點你仍然需要正確的使用它們)。
不幸運的是,並不是每個數據庫都支持事務,因此PDO需要在建立連接時運行在被認為是“自動提交”的模式下。自動提交模式意味著你執行的每個查詢都有它自己隱含的事務處理,無論數據庫支持事務還是因數據庫不支持而不存在事務。如果你需要一個事務,你必須使用 PDO->beginTransaction() 方法創建一個。如果底層驅動不支持事務處理,一個PDOException就會被拋出(與你的異常處理設置無關,因為這總是一個嚴重的錯誤狀態)。在一個事物中,你可以使用 PDO->commit() 或 PDO->rollBack() 結束它,這取決於事務中代碼運行是否成功。
當腳本結束時或一個連接要關閉時,如果你還有一個未處理完的事務,PDO將會自動將其回滾。這是對於腳本意外終止的情況來說是一個安全的方案——如果你沒有明確地提交事務,它將會假設發生了一些錯誤,為了你數據的安全,所以就執行回滾了。
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代號,特定數據庫驅動的錯誤代號和特定數據庫驅動的錯誤說明字符串。
<?php // 修改默認的錯誤顯示級別 $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); ?>
PDO::query() 主要用於有記錄結果返回的操作,特別是select操作。
PDO::exec()主要是針對沒有結果集合返回的操作。如insert,update等操作。返回影響行數。
PDO::lastInsertId()返回上次插入操作最後一條ID,但要注意:如果用insert into tb(col1,col2)values(v1,v2),(v11,v22)..的方式一次插入多條記錄,lastinsertid()返回的只是第一條(v1,v2)插入時的ID,而不是最後一條記錄插入的記錄ID。
PDOStatement::fetch()是用來獲取一條記錄。配合while來遍歷。
PDOStatement::fetchAll()是獲取所有記錄集到一個中。
PDOStatement::fetchcolumn([intcolumn_indexnum])用於直接訪問列,參數column_indexnum是該列在行中的從0開始索引值,但是,這個方法一次只能取得同一行的一列,只要執行一次,就跳到下一行。因此,用於直接訪問某一列時較好用,但要遍歷多列就用不上。
PDOStatement::rowcount()適用於當用query("select...")方法時,獲取記錄的條數。也可以用於預處理中。$stmt->rowcount();
PDOStatement::columncount()適用於當用query("select...")方法時,獲取記錄的列數。
注解:
1、選fetch還是fetchall?
小記錄集時,用fetchall效率高,減少從數據庫檢索次數,但對於大結果集,用fetchall則給系統帶來很大負擔。數據庫要向WEB前端傳輸量太大反而效率低。
2、fetch()或fetchall()有幾個參數:
mixed pdostatement::fetch([int fetch_style[,int cursor_orientation [,int cursor_offset]]])
array pdostatement::fetchAll(int fetch_style)
PDO::beginTransaction — 啟動一個事務 PDO::commit — 提交一個事務 PDO::__construct — 創建一個表示數據庫連接的 PDO 實例 PDO::errorCode — 獲取跟數據庫句柄上一次操作相關的 SQLSTATE PDO::errorInfo — Fetch extended error information associated with the last operation on the database handle PDO::exec — 執行一條 SQL 語句,並返回受影響的行數 PDO::getAttribute — 取回一個數據庫連接的屬性 PDO::getAvailableDrivers — 返回一個可用驅動的數組 PDO::inTransaction — 檢查是否在一個事務內 PDO::lastInsertId — 返回最後插入行的ID或序列值 PDO::prepare — Prepares a statement for execution and returns a statement object PDO::query — Executes an SQL statement, returning a result set as a PDOStatement object PDO::quote — Quotes a string for use in a query. PDO::rollBack — 回滾一個事務 PDO::setAttribute — 設置屬性
Exception::getMessage — 獲取異常消息內容。 Exception::getPrevious — 返回異常鏈中的前一個異常 Exception::getCode — 獲取異常代碼 Exception::getFile — 獲取發生異常的程序文件名稱 Exception::getLine — 獲取發生異常的代碼在文件中的行號 Exception::getTrace — 獲取異常追蹤信息 Exception::getTraceAsString — 獲取字符串類型的異常追蹤信息 Exception::toString — 將異常對象轉換為字符串 Exception::clone — 異常克隆
PDO::PARAM_BOOL 表示一個布爾類型 PDO::PARAM_NULL 表示一個SQL中的NULL類型 PDO::PARAM_INT 表示一個SQL中的INTEGER類型 PDO::PARAM_STR 表示一個SQL中的SQL CHAR,VARCHAR類型 PDO::PARAM_LOB 表示一個SQL中的large object類型 PDO::PARAM_STMT 表示一個SQL中的recordset類型,還沒有被支持 PDO::PARAM_INPUT_OUTPUT Specifies that the parameter is an INOUT parameter for a stored procedure. You must bitwise-OR this value with an explicit PDO::PARAM_* data type. PDO::FETCH_LAZY 將每一行結果作為一個對象返回 PDO::FETCH_ASSOC 僅僅返回以鍵值作為下標的查詢的結果集,名稱相同的數據只返回一個 PDO::FETCH_NAMED 僅僅返回以鍵值作為下標的查詢的結果集,名稱相同的數據以數組形式返回 PDO::FETCH_NUM 僅僅返回以數字作為下標的查詢的結果集 PDO::FETCH_BOTH 同時返回以鍵值和數字作為下標的查詢的結果集 PDO::FETCH_OBJ 以對象的形式返回結果集 PDO::FETCH_BOUND 將PDOStatement::bindParam()和PDOStatement::bindColumn()所綁定的值作為變量名賦值後返回 PDO::FETCH_COLUMN 表示僅僅返回結果集中的某一列 PDO::FETCH_CLASS 表示以類的形式返回結果集 PDO::FETCH_INTO 表示將數據合並入一個存在的類中進行返回 PDO::FETCH_FUNC PDO::FETCH_GROUP PDO::FETCH_UNIQUE PDO::FETCH_KEY_PAIR 以首個鍵值下表,後面數字下表的形式返回結果集 PDO::FETCH_CLASSTYPE PDO::FETCH_SERIALIZE 表示將數據合並入一個存在的類中並序列化返回 PDO::FETCH_PROPS_LATE Available since PHP 5.2.0 PDO::ATTR_AUTOCOMMIT 在設置成true的時候,PDO會自動嘗試停止接受委托,開始執行 PDO::ATTR_PREFETCH 設置應用程序提前獲取的數據大小,並非所有的數據庫哦度支持 PDO::ATTR_TIMEOUT 設置連接數據庫超時的值 PDO::ATTR_ERRMODE 設置Error處理的模式 PDO::ATTR_SERVER_VERSION 只讀屬性,表示PDO連接的服務器端數據庫版本 PDO::ATTR_CLIENT_VERSION 只讀屬性,表示PDO連接的客戶端PDO驅動版本 PDO::ATTR_SERVER_INFO 只讀屬性,表示PDO連接的服務器的meta信息 PDO::ATTR_CONNECTION_STATUS PDO::ATTR_CASE 通過PDO::CASE_*中的內容對列的形式進行操作 PDO::ATTR_CURSOR_NAME 獲取或者設定指針的名稱 PDO::ATTR_CURSOR 設置指針的類型,PDO現在支持PDO::CURSOR_FWDONLY和PDO::CURSOR_FWDONLY PDO::ATTR_DRIVER_NAME 返回使用的PDO驅動的名稱 PDO::ATTR_ORACLE_NULLS 將返回的空字符串轉換為SQL的NULL PDO::ATTR_PERSISTENT 獲取一個存在的連接 PDO::ATTR_STATEMENT_CLASS PDO::ATTR_FETCH_CATALOG_NAMES 在返回的結果集中,使用自定義目錄名稱來代替字段名。 PDO::ATTR_FETCH_TABLE_NAMES 在返回的結果集中,使用自定義表格名稱來代替字段名。 PDO::ATTR_STRINGIFY_FETCHES PDO::ATTR_MAX_COLUMN_LEN PDO::ATTR_DEFAULT_FETCH_MODE Available since PHP 5.2.0 PDO::ATTR_EMULATE_PREPARES Available since PHP 5.1.3. PDO::ERRMODE_SILENT 發生錯誤時不匯報任何的錯誤信息,是默認值 PDO::ERRMODE_WARNING 發生錯誤時發出一條php的E_WARNING的信息 PDO::ERRMODE_EXCEPTION 發生錯誤時拋出一個PDOException PDO::CASE_NATURAL 回復列的默認顯示格式 PDO::CASE_LOWER 強制列的名字小寫 PDO::CASE_UPPER 強制列的名字大寫 PDO::NULL_NATURAL PDO::NULL_EMPTY_STRING PDO::NULL_TO_STRING PDO::FETCH_ORI_NEXT 獲取結果集中的下一行數據,僅在有指針功能時有效 PDO::FETCH_ORI_PRIOR 獲取結果集中的上一行數據,僅在有指針功能時有效 PDO::FETCH_ORI_FIRST 獲取結果集中的第一行數據,僅在有指針功能時有效 PDO::FETCH_ORI_LAST 獲取結果集中的最後一行數據,僅在有指針功能時有效 PDO::FETCH_ORI_ABS 獲取結果集中的某一行數據,僅在有指針功能時有效 PDO::FETCH_ORI_REL 獲取結果集中當前行後某行的數據,僅在有指針功能時有效 PDO::CURSOR_FWDONLY 建立一個只能向後的指針操作對象 PDO::CURSOR_SCROLL 建立一個指針操作對象,傳遞PDO::FETCH_ORI_*中的內容來控制結果集 PDO::ERR_NONE (string) 設定沒有錯誤時候的錯誤信息
<?php $dbh = new PDO('mysql:host=localhost;dbname=access_control', 'root', ''); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->exec('set names utf8'); /*添加*/ //$sql = "INSERT INTO `user` SET `login`=:login AND `password`=:password"; $sql = "INSERT INTO `user` (`login` ,`password`)VALUES (:login, :password)"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':login'=>'kevin2',':password'=>'')); echo $dbh->lastinsertid(); /*修改*/ $sql = "UPDATE `user` SET `password`=:password WHERE `user_id`=:userId"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':userId'=>'7', ':password'=>'4607e782c4d86fd5364d7e4508bb10d9')); echo $stmt->rowCount(); /*刪除*/ $sql = "DELETE FROM `user` WHERE `login` LIKE 'kevin_'"; //kevin% $stmt = $dbh->prepare($sql); $stmt->execute(); echo $stmt->rowCount(); /*查詢*/ $login = 'kevin%'; $sql = "SELECT * FROM `user` WHERE `login` LIKE :login"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':login'=>$login)); while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ print_r($row); } print_r( $stmt->fetchAll(PDO::FETCH_ASSOC)); ?>