1. 程式人生 > >php PDO連線mysql

php PDO連線mysql

最近在linux裝了新的環境,php5.6+mysql5.5+nginx。然後用原來的mysql連結資料庫出現的錯誤。

原因就是說連線資料庫的方法太舊。建議我用mysqli和PDO來連線資料庫。

好吧,咱也不能落後,使用mysqli的確也簡單了不少,但是PDO貌似更簡單。效率也會得到提升。根據官方文件,貌似對於sql注入的一些風險也做了遮蔽。所以今天寫的 部落格就是關於php用PDO連線mysql的一些介紹啦!

【PDO是啥】

PDO是PHP 5新加入的一個重大功能,因為在PHP 5以前的php4/php3都是一堆的資料庫擴充套件來跟各個資料庫的連線和處理,什麼php_mysql.dllphp_pgsql.dll

php_mssql.dllphp_sqlite.dll等等擴充套件來連線MySQLPostgreSQLMS SQL ServerSQLite,同樣的,我們必須藉助 ADOdbPEAR::DBPHPlib::DB之類的資料庫抽象類來幫助我們,無比煩瑣和低效,畢竟,php程式碼的效率怎麼能夠我們直接用C/C++寫的擴充套件效率高捏?所以嘛,PDO的出現是必然的,大家要平靜學習的心態去接受使用,也許你會發現能夠減少你不少功夫哦。



下面說說PDO基於php的版本:

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_ASSOC
-- 關聯陣列形式
PDO::FETCH_NUM -- 數字索引陣列形式
PDO::FETCH_BOTH -- 兩者陣列形式都有,這是預設的

PDO::FETCH_OBJ -- 按照物件的形式,類似於以前的 mysql_fetch_object()

$db->query($sql); 當$sql 中變數可以用$dbh->quote($params); //轉義字串的資料  

php pdo statement

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中的事務

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將會自動將其回滾。這是對於指令碼意外終止的情況來說是一個安全的方案——如果你沒有明確地提交事務,它將會假設發生了一些錯誤,為了你資料的安全,所以就執行回滾了。


PDOException

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常用方法:

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方法:

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