當用PHP訪問數據庫時,除了PHP自帶的數據庫驅動,咱們通常還有兩種比較好的選擇:PDO和MySQLi。在實際開發過程當中要決定選擇哪種首先要對兩者有一個比較全面的瞭解。本文就針對他們的不一樣點進行分析,並對多數據庫類型支持、穩定性、性能等等方面進行對比。php
|
PDO | MySQLi |
Database support | 12 different drivers | MySQL only |
API | OOP | OOP + procedural |
Connection | Easy | Easy |
Named parameters | Yes | No |
Object mapping | Yes | Yes |
Prepared statements (client side) |
Yes | No |
Performance | Fast | Fast |
Stored procedures | Yes | Yes |
// PDO $pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password'); // mysqli, procedural way $mysqli = mysqli_connect('localhost','username','password','database'); // mysqli, object oriented way $mysqli = new mysqli('localhost','username','password','database');
PDO和MySQLi都是經過面向對象的形式提供API,可是同時MySQLi也提供了面向過程的API,這種形式對於新手來講更容易理解。若是你對原生的php mysql 驅動熟悉,你會發現很輕鬆得就能使用MySQLi的接口來替換原來的數據訪問。用PDO的好處是,PDO支持多種數據庫,而MySQLi只支持MySQL,一但你掌握了就你能夠爲所欲爲的使用鏈接多種數據庫。html
PDO比MySQLi最大的優勢就是PDO支持不少種數據庫,而MySQLi只支持MySQLi。要看PDO支持哪些數據庫用下面的代碼:mysql
var_dump(PDO::getAvailableDrivers());
支持多數據庫有什麼好處呢?當你的程序之後想從mysql換成sql server或者oracle時,PDO的優點就能體現出來了,由於換數據庫對於程序接口是透明的,php代碼改動很小,若是你是用MySQLi,那麼全部用到數據庫的地方都要重寫,這樣的改動我也只能呵呵了。sql
PDO命名參數及參數綁定:數據庫
$params = array(':username' => 'test', ':email' => $mail, ':last_login' => time() - 3600); $pdo->prepare(' SELECT * FROM users WHERE username = :username AND email = :email AND last_login > :last_login'); $pdo->execute($params);
而MySQLi的參數綁定:api
$query = $mysqli->prepare(' SELECT * FROM users WHERE username = ? AND email = ? AND last_login > ?'); $query->bind_param('sss', 'test', $mail, time() - 3600); $query->execute();
咱們從上面對比就能夠看出PDO是經過命名參數進行值的綁定,而MySQLi的參數綁定是經過點位符「?」並嚴格按這個問號的順序來綁定值。這樣雖然代碼顯得沒有PDO那種經過名字對應那麼長,可是有一個很差的地方是可讀性和可維護性都下降了,參數個數比較少的時候還不以爲,當參數上了10多個或者更多的狀況就比較痛苦了,你必需要按問號的順序來一個一個對應來賦值,萬一其中一個位錯了,後面的都跟着錯了。安全
不幸的是MySQLi不支持PDO那樣的命名參數綁定。oracle
基於數據庫的開發通常都是從數據庫中讀取數據而後把這些數據用一個對象來承載。PDO和MySQLi都支持對象映射,假設有一個User類,它有一些屬性對應到數據庫。app
class User { public $id; public $first_name; public $last_name; public function info() { return '#'.$this->id.': '.$this->first_name.' '.$this->last_name; } }
若是沒有對象映射,咱們要讀取數據以後,一個一個字段的賦值,這是很繁瑣的。ide
下面請看兩者使用對象的代碼:
$query = "SELECT id, first_name, last_name FROM users"; // PDO $result = $pdo->query($query); $result->setFetchMode(PDO::FETCH_CLASS, 'User'); while ($user = $result->fetch()) { echo $user->info()."\n"; } // MySQLI, procedural way if ($result = mysqli_query($mysqli, $query)) { while ($user = mysqli_fetch_object($result, 'User')) { echo $user->info()."\n"; } } // MySQLi, object oriented way if ($result = $mysqli->query($query)) { while ($user = $result->fetch_object('User')) { echo $user->info()."\n"; } }
兩者均可以防止sql注入。咱們先看一個例子。
$_GET['username'] = "'; DELETE FROM users; /*"
當用戶輸入的username參數的值爲上面的值("'; DELETE FROM users; /*"),若是你沒有對這個值作任何處理,用戶就成功將delete語句注入,那麼user表的記錄就會被所有刪除。
// PDO, "manual" escaping $username = PDO::quote($_GET['username']); $pdo->query("SELECT * FROM users WHERE username = $username"); // mysqli, "manual" escaping $username = mysqli_real_escape_string($_GET['username']); $mysqli->query("SELECT * FROM users WHERE username = '$username'");
上面採用了PDO和MySQLi的API自帶的函數對獲取到的參數的值進行了轉義。
下面推薦更加高效安全的prepared statement參數綁定的方式:
// PDO, prepared statement $pdo->prepare('SELECT * FROM users WHERE username = :username'); $pdo->execute(array(':username' => $_GET['username'])); // mysqli, prepared statements $query = $mysqli->prepare('SELECT * FROM users WHERE username = ?'); $query->bind_param('s', $_GET['username']); $query->execute();
因爲PDO可以支持其它非MySQL的數據庫,而MySQLi專門針對MySQL設計的,因此MySQLi相對於PDO性能稍微好一些。可是PDO和MySQLi都仍是沒有PHP原生的MySQL擴展快。可是這樣性能比較其實意義不太大,由於它們都是至關快了,若是你的程序性能要求不是特別苛刻話,三者均可以知足你。至於你要選擇哪種就要你根據的實踐狀況進行權衡。
PDO支持12種數據庫驅動和命名參數綁定是其最大優勢,經過上面的對比,我相信你也知道了你在本身的項目中會使用哪種鏈接數據庫了?