1. 程式人生 > >PDO vs. MySQLi 選擇哪一個?(PDO vs. MySQLi: Which Should You Use?)

PDO vs. MySQLi 選擇哪一個?(PDO vs. MySQLi: Which Should You Use?)

本文並非直譯

用Php訪問資料的時候,你選擇MySQLi和PDO,在選擇之前,你應該知道些什麼呢?

這篇文章將會介紹這兩種方式的不同點,資料庫的支援、穩定性、效能等問題。

概述

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

(請注意,這兩個連線將貫穿全文)

API支援

PDO和MySQLi都提供了面向物件的API,但是MySQLi也提供了面向過程程式設計的API(就是函式式)所以對於新手非常易於理解,如果你使用原始的MySQL的API,那麼遷移到MySQLi也非常容易。另一方面,一旦你選擇了PDO,你就可以用在任何你想要使用的資料庫上。

資料庫支援

PDO比MySQLi的核心優勢在於資料庫的驅動支援上。再寫這篇文章的時候,PDO支援12種資料庫驅動,而MySQLi只支援MySQL。

通過下面的程式碼可以打印出當前PDO支援的資料庫驅動

var_dump(PDO::getAvailableDrivers());

這意味著什麼?

如果你選擇了使用PDO的方式,當需要換資料庫的時候,遇到不存在或者不支援的方法,你只需要更改連線字串,以及一些查詢語句即可,而MySQLi,則需要重新所有的查詢以及連線方式。

名稱式引數

這是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的方式:
$query = $mysqli->prepare('
   SELECT * FROM users
   WHERE username = ?
   AND email = ?
   AND last_login > ?');
 
$query->bind_param('sss', 'test', $mail, time() - 3600);
$query->execute();

這個問號(?)繫結引數看上去很短,但是相比名稱式引數缺少了靈活性,而且迫使開發者必須保證引數的順序,有時候讓人覺得很蛋疼。

而且不幸的是MySQLi並不支援名稱式引數。

物件對映

PDO和MySQLi都可以將結果對映成物件。下面自定義一個User類和一些屬性,並且欄位和資料庫的表字段對應。

class User {
   public $id;
   public $first_name;
   public $last_name;
 
   public function info()
   {
      return '#'.$this->id.': '.$this->first_name.' '.$this->last_name;
   }
}

如果沒有用物件對映,如果在使用inof()方法前,就要手工的給屬性賦值,或者在初始化的時候賦值。

而採用物件對映就可以直接完成

$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方式注入的語句

$_GET['username'] = "'; DELETE FROM users; /*"

如果我們不對這個引數進行處理,則問題是顯而易見的。而且PDO和MySQLi都支援多重查詢。這樣可能導致若干資料被刪除掉。

對$_GET資料處理

// 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::quote不僅轉義了字串,而且還加了單引號,而MySQLi只是轉義了字串,需要自己手動加單引號。

下面是prepared statements的方式查詢

// 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();

推薦採用prepared statements的方式繫結查詢來代替PDO::quote() 和 mysqli_real_escape_string().

效能

PDO和MySQLi都有非常好的效能。在非prepared statements的基準測試下,MySQLi略快2.5%,而prepared statements下是6.5%,可以說對於效能無關緊要。如果你真的非常介意這一點點效能的話,而自帶的MySQL擴充套件比兩者都快,你可以考慮下它。

總結

最後,綜合情況PDO在這場對比中勝出,支援12種不同資料庫驅動程式(18種不同的資料庫)和………………為以上提到的……

所以結論就是:如果你現在還在使用MySQLi,你可以考慮換了。

原文連結地址參考: