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() 方法返回最近生成的错误消息。没有错误返回的就是空字符串。消息语言依赖于 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()
}