PHP 在初期就支援 MySQL了,在它的第2版本中就包含了一個API。因為它倆的結合太普遍了,所以該擴充預設就是開啟的。不過 PHP 5 發布了一個更新的 MySQL 擴充,叫 MySQL Improved,簡稱 mysqli。
為什麼要出新擴充呢?原因有兩方面。首先MySQL的快速發展,那些依賴舊擴充的使用者沒法利用新特性,如prepared statements、進階串連選項以及安全提升。第二,雖然那箇舊擴充當然用起來也不錯,但許多人認為過程化的介面過時了,他們更喜歡物件導向的介面,因為不僅能與其他應用程式更緊密地整合,還能根據需要擴充此介面。為解決這些不足,MySQL開發人員決定是時候改造一下那個擴充,不僅僅修改了內部行為實現了效能提升,還引入了額外的特性促進了更新版本的MySQL中的可用特性的使用。
幾點關鍵的改進:
# 物件導向:mysqli擴充被封裝到一系列類,從而鼓勵使用一種被很多人認為比PHP傳統的過程化方法更方便也更高效的編程範型。但是那些喜歡過程化範型的人也不要擔心,因為它也提供了一個傳統的過程化介面。
# prepared statements:能夠阻止SQL注入攻擊。它消除了那些重複執行的查詢的開銷和不方便。
# 事務支援:儘管PHP最初的MySQL擴充也能支援事務功能,mysqli 擴充提供了這些功能的一個物件導向的介面。
# 增強調試功能:mysqli 擴充聽過了許多方法用於調試查詢,更使開發過程更高效。
# 內嵌的伺服器支援:MySQL 4.0 release 引入了一個內嵌的MySQL server 庫,那些感興趣的使用者就可以在用戶端應用例如傳統型程式中運行一個完整的MYSQL伺服器了。mysqli 擴充提供了一些方法用於串連和操作這些內嵌的MySQL伺服器。
# 主/從支援:從 MySQL 3.23.15 開始,MySQL 就提供了對複製的支援。使用 mysqli 擴充,你可以保證查詢會被轉到一個複製配置中的主伺服器上。
那些對最初的MySQL擴充熟悉的使用者會發現增強mysqli擴充很眼熟,幾乎是一樣的命名規範。例如,資料庫連接函數叫mysqli_connect而不是mysql_connect。
1、安裝的先決條件
從PHP 5開始,MySQL支援不在於標準PHP分發包捆綁。因此,需要顯式配置PHP才能利用此擴充。
1.1、在Linux/UNIX中啟用mysqli擴充
配置PHP的時候使用 --with-mysqli 標識。它應該指向 MySQL 4.1 以及更高版本中的 mysql_config 程式的位置。
1.2、在Windows上開啟mysqli擴充
需修改php.ini,取消這行前面的注釋:extension=php_mysqli.dll,如果沒有的話,加上這一行。當然,啟用任何擴充之前,要確保PHP的 extension_dir指令指向適當的目錄。
1.3、使用MYSQL本地驅動程式
一直以來,PHP 要求運行PHP程式的那台伺服器上要安裝 MySQL client library,而不論MYSQL伺服器恰好在本地或是在其他位置。PHP 5.3 除去了該要求,它引入了一個新的MySQL驅動,叫作MySQL Native Driver,也被叫做mysqlnd,它比剛才說的那個驅動要有很多優勢。它不是一個新的API,而是一個新的“導管”,現有的API(mysql,mysqli,PDO_MySQL)可以利用這個導管與一個MySQL伺服器通訊。建議用mysqlnd,而不要使用其他驅動程式(除非你有非常充分的理由)。
要將 mysqlnd和某個擴充一起使用,你需要重新編譯PHP,例如:--with-mysqli=mysqlnd。也可以多指定幾個,如%>./configure --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd
mysqlnd 驅動也有一些限制。當前它不提供壓縮以及SSL支援。
1.4、系統管理使用者許可權
當一個指令碼初始化一個到MySQL伺服器的串連時,許可權就會被傳遞和檢驗。還有在提交需要許可權檢驗的命令時也是一樣。不過,你只需在串連時確認執行使用者;除非後來搞了一個新串連,否則指令碼的後續執行都將一直是那個使用者。
1.5、使用範例資料
學新知識時加上一些例子就簡單了。資料庫:corporate;表:products
CREATE TABLE products (
id INT NOT NULL AUTO_INCREMENT,
sku VARCHAR(8) NOT NULL,
name VARCHAR(100) NOT NULL,
price DECIMAL(5,2) NOT NULL,
PRIMARY KEY(id)
)
===========================================================================
2、使用 mysqli 擴充
2.1、建立和中斷連線
先要串連到伺服器,然後選擇一個資料庫,之後是關閉串連。物件導向、過程化 這2種風格都是可以的。
用物件導向介面和MySQL伺服器互動,首先要用mysqli類的構造器執行個體化它。
mysqli([string host [, string username [, string pswd
[, string dbname [, int port, [string socket]]]]]])
過去運用過PHP和MySQL的使用者會發現該建構函式的許多參數和傳統的mysql_connect()函數是一樣的。
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
如果某個時刻,你想切換到其他伺服器或選擇另一個資料庫,你可以用 connect()和select_db()方法。connect()方法的參數和mysqli類的建構函式一樣。
// Instantiate the mysqli class
$mysqli = new mysqli();
// Connect to the database server and select a database
$mysqli->connect('localhost', 'root', '', 'corporate');
----------------------------------------------------------------------------------
或者
// Connect to the database server
$mysqli = new mysqli('localhost', 'catalog_user', 'secret');
// Select the database
$mysqli->select_db('corporate');
一但指令碼完成執行,任何開啟的資料庫連接會自動關閉,資源也會被恢複。然而,也有可能一個頁面在執行的過程中需要用到多個資料庫連接,這些串連都需要正確地被關閉。即使只使用了一個串連,也應該在指令碼的最後將其關閉,這是一種很好的實踐方法。$mysqli->close()。
2.2、處理串連錯誤
應當仔細監控串連錯誤,並相應地做出應對措施。mysqli 擴充提供了一些特性,能夠被用來捕捉錯誤訊息,還有一種辦法就是利用異常。例如,mysqli_connect_errno() 和 mysqli_connect_error() 就能夠被用來診斷和顯示MySQL串連錯誤資訊。
2.3、擷取錯誤訊息
2.3.1、擷取錯誤碼
errno() 方法返回上一次MySQL函數執行過程中產生的錯誤碼。0表示沒有錯誤。
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
printf("Mysql error number generated: %d", $mysqli->errno);
?>
2.3.2、擷取錯誤訊息
error() 方法返回最近產生的錯誤訊息。沒有錯誤返回的就是Null 字元串。訊息語言依賴於 Mysql 資料庫伺服器。
2.4、在一個獨立檔案中儲存串連資訊
在安全編程實踐的思想中,定期修改密碼是個不錯的主意。還有就是有很多要訪問資料庫的指令碼,一個個修改太麻煩了。辦法是存在單獨的一個檔案中,必要時將其包含到你當前的檔案中。
例如,可以將 mysqli 建構函式放在一個標頭檔中(mysql.connect.php):
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
?>
然後在其他檔案中包含它:
include 'mysql.connect.php';
// begin database selection and queries.
?>
==============================================================================
3、與資料庫互動
3.1、向資料庫發送查詢
用query()方法。其形式為mixed query(string query [, int resultmode])。其中可選的 resultmode 參數用於修改該方法的行為,它有2種值:
. MYSQLI_STORE_RESULT:是預設值。將結果集返回為一個緩衝集,意味著整個結果集立刻就能準備用於導航了。雖然對記憶體的消耗有些大,但它允許你立刻就能使用整個結果集,所以當你嘗試分析以及管理結果集時很有用。例如,你可能想知道從一個查詢中返回了多少行資料,或者你可能想立即調到結果集中的某一行。
. MYSQLI_USE_RESULT:將結果集返回為一個 unbuffered set,意味著會根據需要從伺服器擷取資料。對於大結果集,這提升了效能,但它無法決定返回了多少行資料,也不能調到某個行。
3.1.1 擷取資料
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
// Create the query
$query = 'SELECT sku, name, price FROM products ORDER by name';
// Send the query to MySQL
$result = $mysqli->query($query, MYSQLI_STORE_RESULT);
// Iterate through the result set
while(list($sku, $name, $price) = $result->fetch_row())
printf("(%s) %s: \$%s
", $sku, $name, $price);
?>
3.1.2、插入、更新,刪除資料
也是用的 query() 方法。
$result = $mysqli->query($query, MYSQLI_STORE_RESULT);
printf("%d rows have been deleted.", $mysqli->affected_rows);
當然,假設串連使用者提供了足夠的憑證,你完全可以執行希望執行的任何查詢,包括建立和修改資料庫、表和索引,甚至可以完成MySQL管理工作,如為使用者建立和賦予許可權。
3.1.3、釋放查詢記憶體
有時你擷取到了一個特別大的結果集,那麼就要在完成處理後,很有必要釋放該結果集所請求的記憶體,用 free() 方法就行了,之後該結果集就不能用了。$result->free();
3.2、解析查詢結果
3.2.1、將結果抓取到對象中
while ($row = $result->fetch_object())
{
$name = $row->name;
$sku = $row->sku;
$price = $row->price;
printf("(%s) %s: %s
", $sku, $name, $price)";
}
3.2.2、用索引和關聯陣列擷取結果
fetch_array() 是同時都是,fetch_row() 是索引數組。
它們的方法原型如下:
class mysqli_result {
mixed fetch_array ([int resulttype])
}
class mysqli_result {
mixed fetch_row()
}
其中resulttype的值可以是MYSQLI_ASSOC或MYSQLI_NUM或MYSQLI_BOTH。
【
MYSQLI_ASSOC:欄位名就是key,欄位內容就是值。
MYSQLI_NUM:順序由查詢指定的欄位名順序決定。如果是 * ,也就是查所有欄位,那就是根據表定義中的欄位順序。
MYSQLI_BOTH:是預設值。
】
$query = 'SELECT sku, name FROM products ORDER BY name';
$result = $mysqli->query($query);
while ($row = $result->fetch_array(MYSQLI_ASSOC))
{
$name = $row['name'];
$sku = $row['sku'];
echo "Product: $name ($sku)
";
}
或
while ($row = $result->fetch_array(MYSQLI_NUM))
{
$sku = $row[0];
$name = $row[1];
$price = $row[2];
printf("(%s) %s: %d
", $sku, $name, $price);
}
3.3 確定選擇的行數|受影響的行數
你希望知道一個SELECT查詢返回的行數或者受到INSERT、UPDATE或DELETE查詢影響的行數。
. num_rows() 方法用於確定從一個SELECT查詢語句返回了多少行資料。例如:
$query = 'SELECT name FROM products WHERE price > 15.99';
$result = $mysqli->query($query);
printf("There are %f product(s) priced above \$15.99.", $result->num_rows);
. affected_rows() 方法用於確定受INSERT、UPDATE以及DELETE查詢影響的行數。
3.4、使用 Prepared Statements
不斷重複執行一個查詢,每次用的是不同的參數值是很常見的。然而,使用傳統的 query() 方法再加上迴圈來實現不僅開銷很大(因為需要重複解析幾乎一樣的查詢以檢驗合法性),而且編碼也不方便(因為需要為每次迭代使用新值重新設定查詢),MySQL 4.1 引入了 prepared statements,它可以用低得多的開銷和更少的代碼實現上述任務。
有2種 prepared statements:
. Bound parameters:它允許你將一個查詢放到 MySQL 伺服器上,只需將變化的資料重複地發送到伺服器上,再整合到查詢中執行。例如,假設你建立了一個 web 程式,允許使用者管理商店商品,為快速啟動初始化過程,可以建立一個表單,最多接受 20 個產品的名稱、ID、價格和描述,就適用於此情況。
. Bound results:它允許你將 PHP 變數綁定到所擷取的相應欄位,從而使用索引數組或關聯陣列從結果集中提取資料,然後在必要時使用這些變數。
3.4.1、準備用於執行的Statement
不管你是用 bound-parameter 還是 bound-result prepared statement,你需要先準備好用於執行的statement,就是用 prepare() 方法。
// Create a new server connection
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
// Create the query and corresponding placeholders
$query = "SELECT sku, name, price, description
FROM products ORDER BY sku";
// Create a statement object
$stmt = $mysqli->stmt_init();
// Prepare the statement for execution
$stmt->prepare($query);
.. Do something with the prepared statement
// Recuperate the statement resources
$stmt->close();
// Close the connection
$mysqli->close();
?>
3.4.2、執行 Prepared Statement
一旦 statement 準備好後,就需要執行它了。何時執行取決於你希望用綁定參數還是綁定結果。如果是前者,將在綁定參數之後執行語句。如果是後者,將在綁定結果之前執行此方法。2種方式中語句的執行都是通過 execute() 方法完成的。
3.4.3、 回收 Prepared Statement 資源【用 close() 方法】
3.4.4、綁定參數
當用的是 bound-parameter prepared statement,你需要調用 bind_param() 方法將變數名綁定到相應的欄位。其原型如下:
class stmt {
boolean bind_param(string types, mixed &var1 [, mixed &varN])
}
types 參數表示其後各個變數(也就是 &var1、...、&varN 表示)的資料類型,該參數是必需的,以確保向伺服器發送時能最有效地實現資料編碼。目前支援4種類型碼。
. i :所有 INTEGER 類型
.d :DOUBLE 和 FLOAT 類型
.b : BLOB 類型
.s : 所有其他類型(包括字串)
舉個例子:
// Create a new server connection
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
// Create the query and corresponding placeholders
$query = "INSERT INTO products SET id=NULL, sku=?,
name=?, price=?";
// Create a statement object
$stmt = $mysqli->stmt_init();
// Prepare the statement for execution
$stmt->prepare($query);
// Bind the parameters
$stmt->bind_param('ssd', $sku, $name, $price);
// Assign the posted sku array
$skuarray = $_POST['sku'];
// Assign the posted name array
$namearray = $_POST['name'];
// Assign the posted price array
$pricearray = $_POST['price'];
// Initialize the counter
$x = 0;
// Cycle through the array, and iteratively execute the query
while ($x < sizeof($skuarray)) {
$sku = $skuarray[$x];
$name = $namearray[$x];
$price = $pricearray[$x];
$stmt->execute();
}
// Recuperate the statement resources
$stmt->close();
// Close the connection
$mysqli->close();
?>
3.4.5、綁定變數
當 查詢 準備好並且也執行過了,就可以將一些變數綁定到取回的欄位中。用的是 bind_result() 方法。其原型如下:
class mysqli_stmt {
boolean bind_result(mixed &var1 [, mixed &varN])
}
例如,假設你想要返回 products 表中前 30 個產品的一個列表。下面的代碼就是將變數 $sku、$name 和 $price綁定到取回的欄位上。
// Create a new server connection
$mysqli = new mysqli('localhost', 'catalog_user', 'secret', 'corporate');
// Create query
$query = 'SELECT sku, name, price FROM products ORDER BY sku';
// Create a statement object
$stmt = $mysqli->stmt_init();
// Prepare the statement for execution
$stmt->prepare($query);
// Execute the statement
$stmt->execute();
// Bind the result parameters
$stmt->bind_result($sku, $name, $price);
// Cycle through the results and output the data
while($stmt->fetch())
printf("%s, %s, %s
", $sku, $name, $price);
// Recuperate the statement resources
$stmt->close();
// Close the connection
$mysqli->close();
?>
3.4.6、從 Prepared Statements 擷取資料行
fetch() 方法從 prepared statement result 中擷取每一行,並將欄位賦值到綁定結果中。其原型如下:
class mysqli {
boolean fetch()
}
============================================================================
4、執行資料庫事務
4.1、開啟自動認可模式
class mysqli {
boolean autocommit(boolean mode)
}
傳 TRUE 就是啟用,FALSE 就是禁用。
4.2、提交一個事務
class mysqli {
boolean commit()
}
4.3、復原一個事務
class mysqli {
boolean rollback()
}