php與mysql的連接有三種API接口,分別是:PHP的MySQL擴展 、PHP的mysqli擴展 、PHP數(shù)據(jù)對象(PDO) ,下面針對以上三種連接方式做下總結(jié),以備在不同場景下選出最優(yōu)方案。
一、特性及對比
PHP的MySQL擴展是設(shè)計開發(fā)允許PHP應(yīng)用與MySQL數(shù)據(jù)庫交互的早期擴展。mysql擴展提供了一個面向過程 的接口,并且是針對MySQL4.1.3或更早版本設(shè)計的。因此,這個擴展雖然可以與MySQL4.1.3或更新的數(shù)據(jù)庫服務(wù)端 進行交互,但并不支持后期MySQL服務(wù)端提供的一些特性。由于太過古老,又不安全,所以已被后來的mysqli完全取代。
PHP的mysqli擴展,我們有時稱之為MySQL增強擴展,可以用于使用 MySQL4.1.3或更新版本中新的高級特性。其特點為:面向?qū)ο蠼涌?、prepared語句支持、多語句執(zhí)行支持、事務(wù)支持 、增強的調(diào)試能力、嵌入式服務(wù)支持 、預(yù)處理方式完全解決了sql注入的問題。不過其也有缺點, 就是只支持mysql數(shù)據(jù)庫。如果你要是不操作其他的數(shù)據(jù)庫,這無疑是最好的選擇。
PDO是PHP Data Objects的縮寫,其是PHP應(yīng)用中的一個數(shù)據(jù)庫抽象層規(guī)范。PDO提供了一個統(tǒng)一的API接口可以使得你的PHP應(yīng)用不去關(guān)心具體要 連接的數(shù)據(jù)庫服務(wù)器系統(tǒng)類型。也就是說,如果你使用PDO的API,可以在任何需要的時候無縫切換數(shù)據(jù)庫服務(wù)器,比如從oracle 到MySQL,僅僅需要修改很少的PHP代碼。其功能類似于JDBC、ODBC、DBI之類接口。同樣,其也解決了sql注入問題,有很好的安全性。不過 他也有缺點,某些多語句執(zhí)行查詢不支持(不過該情況很少)。
為了與MySQL數(shù)據(jù)庫服務(wù)端進行交互,mysql擴展,mysqli擴展, PDO MySQL驅(qū)動都使用了實現(xiàn)了必要的協(xié)議的底層庫。以前,可用的庫只有MySQL客戶端庫和libmysql。
然而,libmysql包含的接口沒有針對與PHP的應(yīng)用交互進行優(yōu)化,libmysql 是早期為C應(yīng)用程序設(shè)計的?;谶@個原因,MySQL Native驅(qū)動mysqlnd,作為libmysql的一個 針對PHP應(yīng)用的修改版本被開發(fā)。
mysql,mysqli以及PDO Mysql驅(qū)動都可以各自配置使用 libmysql或者mysqlnd。mysqlnd作為一個專門設(shè)計 用于PHP系統(tǒng)的庫,它在內(nèi)存和速度上都比libmysql有很大提升。非常希望你去嘗試這些提升。
特性比較
下表比較了PHP中三種主要的MySQL連接方式的功能:
PHP的mysqli擴展 | PDO (使用PDO MySQL驅(qū)動和MySQL Native驅(qū)動) | PHP的mysql擴展 | |
---|---|---|---|
引入的PHP版本 | 5.0 | 5.0 | 3.0之前 |
PHP5.x是否包含 | 是 | 是 | 是 |
MySQL開發(fā)狀態(tài) | 活躍 | 在PHP5.3中活躍 | 僅維護 |
在MySQL新項目中的建議使用程度 | 建議 - 首選 | 建議 | 不建議 |
API的字符集支持 | 是 | 是 | 否 |
服務(wù)端prepare語句的支持情況 | 是 | 是 | 否 |
客戶端prepare語句的支持情況 | 否 | 是 | 否 |
存儲過程支持情況 | 是 | 是 | 否 |
多語句執(zhí)行支持情況 | 是 | 大多數(shù) | 否 |
是否支持所有MySQL4.1以上功能 | 是 | 大多數(shù) | 否 |
簡單來說就是 : mysqli(首選) pdo_mysql(建議) mysql(不建議)
下面是我這個星期做過的幾種數(shù)據(jù)庫連接的方式:
Mysql連接:
<?php $conn = @ mysql_connect("localhost", "root", "") or die("數(shù)據(jù)庫連接錯誤"); mysql_select_db("bbs", $conn); mysql_query("set names 'utf8'"); echo "數(shù)據(jù)庫連接成功"; ?>
Mysqli連接:
<?php
$conn = mysqli_connect('localhost', 'root', '', 'bbs'); if(!$conn){ die("數(shù)據(jù)庫連接錯誤" . mysqli_connect_error()); }else{ echo"數(shù)據(jù)庫連接成功"; } ?>
Pdo連接:
<?php try{ $pdo=new pdo("mysql:host=localhost;dbname=bbs","root",""); }catch(PDDException $e){ echo"數(shù)據(jù)庫連接錯誤"; } echo"數(shù)據(jù)庫連接成功"; ?>
普通的mysql方法在安全性方面應(yīng)該不是很好,每次需要考慮sql注入的問題,而且速度不是很贊。而mysqli是在mysql基礎(chǔ)上進行改進的一次,較好的解決了sql注入問題。
pdo則是最新的數(shù)據(jù)庫抽象方法,pdo高度抽象了數(shù)據(jù)庫操作,項目使用pdo方法可以方便的進行遷移,在不同的數(shù)據(jù)庫之間進行遷移。
在高負載的情況下.PDO開啟長連接能夠得到一個相對穩(wěn)定的負載“值”。但是效率卻不是最高的。
mysql最快。mysqli其次。只是mysql和mysqli在高并發(fā)、系統(tǒng)高負載的時候。其所承擔的負載也是很可觀的。PDO則不會。
書寫風(fēng)格 | 面向?qū)ο?/td> | 拋異常 | |
php_mysqli | 函數(shù)名用下劃線,比如fetch_all | 可以oop,也可以opp | 否,只能false |
pdo | 函數(shù)名用駝峰,比如fetchAll | oop | 可以throw,也可false或false加warnnig |
php_pgsql | 函數(shù)名用下劃線,比如pg_fetch_all | opp | 否,只能false |
其次pdo是面向?qū)ο蟮?,當有錯誤的時候可以拋出異常,而且可以自定義異常拋出。
php_mysqli 與 pdo 性能對比:(查找自互聯(lián)網(wǎng))
PHP的mysqli擴展 | PDO (使用PDO MySQL驅(qū)動和MySQL Native驅(qū)動) | PHP的mysql擴展 | |
---|---|---|---|
引入的PHP版本 | 5.0 | 5.0 | 3.0之前 |
PHP5.x是否包含 | 是 | 是 | 是 |
MySQL開發(fā)狀態(tài) | 活躍 | 在PHP5.3中活躍 | 僅維護 |
在MySQL新項目中的建議使用程度 | 建議 - 首選 | 建議 | 不建議 |
API的字符集支持 | 是 | 是 | 否 |
服務(wù)端prepare語句的支持情況 | 是 | 是 | 否 |
客戶端prepare語句的支持情況 | 否 | 是 | 否 |
存儲過程支持情況 | 是 | 是 | 否 |
多語句執(zhí)行支持情況 | 是 | 大多數(shù) | 否 |
是否支持所有MySQL4.1以上功能 | 是 | 大多數(shù) | 否 |
PDO使用說明:
PDO::prepare()
官方文檔:http://www.php.net/manual/zh/pdo.prepare.php
適用:多次查詢使用相同的條件字段和結(jié)果字段。這時候比PDO::query()性能高。
轉(zhuǎn)義:value無需手動轉(zhuǎn)義,PDO會自動進行轉(zhuǎn)義,不用擔心SQL注入。(開啟query log可以看到語句的確已轉(zhuǎn)義)
缺點:由于標識符(列名表名)是手寫的SQL,要自己加引用符反勾號`。
PDO::prepare()模擬處理的時候不會通過數(shù)據(jù)庫,所以不知道語法錯誤,不會返回錯誤或拋異常。什么時候是真處理,什么時候是模擬處理, 官方手冊中未找到說明。輸入任意的SQL都不出錯……所以目前不要指望prepare返回錯誤,PDOStatement::execute()時才會返 回錯誤。
可以用以下代碼測試對比mysql數(shù)據(jù)庫的執(zhí)行效率
<?php /** * 測試pdo和mysqli的執(zhí)行效率 */ header("Content-type:text/html;charset=utf-8"); //通過pdo鏈接數(shù)據(jù)庫 $pdo_startTime = microtime(true); $pdo = new PDO("mysql:host=localhost;dbname=test","root","1234",array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES'utf8';")); for($i=1;$i<=100;$i++){ $title = "pdo標題".$i; $content = "pdo內(nèi)容".$i; $addtime = time(); $user_id = $i; $pdo_sql = "INSERT INTO `article`(`title`,`content`,`addtime`,`user_id`) VALUES(:title,:content,:addtime,:user_id)"; $sth = $pdo->prepare($pdo_sql); $sth->bindParam(':title',$title); $sth->bindParam(':content',$content); $sth->bindParam(':addtime',$addtime); $sth->bindParam(':user_id',$user_id); $sth->execute(); } $pdo_endTime = microtime(true); $pdo_time = $pdo_endTime - $pdo_startTime; echo $pdo_time; echo "<hr/>"; //通過mysql鏈接數(shù)據(jù)庫 $mysqli_startTime = microtime(true); $mysqli = mysqli_connect("localhost","root","1234","test") or die("數(shù)據(jù)連接失敗"); mysqli_query($mysqli,"set names utf8"); for($i=1;$i<=100;$i++){ $title = "mysqli標題".$i; $content = "mysqli內(nèi)容".$i; $addtime = time(); $user_id = $i; $sql = "INSERT INTO `article`(`title`,`content`,`addtime`,`user_id`) VALUES('".$title."','".$content."',".$addtime.",".$user_id.")"; mysqli_query($mysqli,$sql); } $mysqli_endTime = microtime(true); $mysqli_time = $mysqli_endTime - $mysqli_startTime; echo $mysqli_time; echo "<hr/>"; if($pdo_time > $mysqli_time){ echo "pdo的執(zhí)行時間是mysqli的".round($pdo_time/$mysqli_time)."倍"; }else{ echo "mysqli的執(zhí)行時間是pdo的".round($mysqli_time/$pdo_time)."倍"; }
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答!! 點擊進入論壇