10.1 MySQL数据库访问函数
PHP5提供了一组MySQLi函数,可以实现连接MySQL数据库、执行SQL语句、返回查询结果集等操作。
要在PHP使用MySQLi函数,需要打开php.ini进行配置。找到下面的配置项:
;extension=php_mysqli.dll
去掉前面的注释符号(;),然后保存php.ini。将php.ini复制到Windows目录下,然后重新启动Apache服务,就可以在PHP中使用MySQLi函数了。
10.1.1 连接到MySQL数据库
在访问数据库时,首先需要创建一个到数据库服务器的MySQLi对象,通过它建立到数据库的连接。在PHP5中,可以通过多种方式创建到数据库的连接。
1.使用mysqli_connect()函数
使用mysqli_connect()函数创建到MySQL数据库的连接对象的方法如下:
$mysqli = mysqli_connect(数据库服务器, 用户名, 密码, 数据库名)
创建Connection对象后,还需要设置具体的属性,连接到指定的数据库。例如,要访问本地的数据库MySQLDB,用户名为root,密码为pass,代码如下:
$conn = mysqli_connect("localhost", "root", "pass", "MySQLDB");
2.声明mysqli对象
可以使用声明mysqli对象的方法来创建连接对象,方法如下:
$mysqli = mysqli (数据库服务器, 用户名, 密码, 数据库名)
3.使用mysqli_init()函数
使用mysqli_init()函数也可以连接到数据库,具体方法如下:
$mysqli = mysqli_init();
通过MySQLi对象的options()函数可以设置连接选项,语法如下:
bool mysqli::options ( int $option , mixed $value )
参数$option用于指定连接选项。常用的连接选项常量如表10-1所示。
表10-1 常用的连接选项常量
例如,将超时时间设置为5s,代码如下:
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);
使用$mysqli->real_connect()函数可以建立到数据库的连接,基本语法如下:
$mysqli->real_connect(数据库服务器, 用户名, 密码, 数据库名);
如果连接出现错误,可以使用 mysqli_connect_errno()函数获取错误编码,也可以使用mysqli_connect_error()函数获取错误的描述信息。
使用 mysqli_get_host_info($conn)函数可以获取连接对象$conn 中包含的数据库服务器信息。在使用数据库连接完成后,可以调用mysqli_close()函数关闭到数据库的连接。
【例10-1】 连接MySQL数据库的示例程序。
<?php
$conn = mysqli_connect("localhost", "root", "1234", "MySQLDB");
if (empty($conn)) {
die("mysqli_connect failed: " . mysqli_connect_error());
}
echo("connected to " . mysqli_get_host_info($conn));
mysqli_close($conn);
?>
die()函数等同于exit()函数, 功能是输出一个消息并且退出当前脚本。
如果使用正确的数据库参数,即MySQLDB数据库存在,用户root的密码为pass,则上面代码的输出结果如下:
connected to localhost via TCP/IP
如果使用错误的用户名或密码,则输出结果如下:
mysqli_connect failed: Access denied for user 'root'@'localhost' (using password: YES)
如果连接到不存在的数据库,则输出结果如下:
mysqli_connect failed: Unknown database 'mysqldb'
10.1.2 执行SQL语句
可以使用 mysqli_query()函数或连接对象的 query()函数来执行 SQL 语句,既可以执行INSERT、DELETE、UPDATE等更新数据库的语句,也可以执行查询数据的SELECT语句。
mysqli_query()函数的基本语法如下:
返回结果集 mysqli_query(连接对象, SQL语句);
连接对象的query()函数的基本语法如下:
返回结果集 query(SQL语句);
1.执行非查询语句
当执行的SQL语句为INSERT、DELETE、UPDATE等非查询语句时,无须考虑返回结果集。
【例10-2】 在数据库MySQLDB中创建一个用户信息表Users,用来保存系统用户信息。表Users的结构如表10-2所示。
表10-2 表Users的结构
可以使用下面的程序来创建表Users:
<?PHP
$conn = mysqli_connect("localhost", "root", "pass", "MySQLDB");
if (empty($conn)) {
die("mysqli_connect failed: " . mysqli_connect_error());
}
//执行CREATE TABLE 语句
$sql ="CREATE TABLE IF NOT EXISTS Users (UserName VARCHAR(50) PRIMARY KEY, UserPwd VARCHAR(50), ShowName VARCHAR(50))";
$conn->query($sql);
//关闭连接
mysqli_close($conn);
?>
假定此脚本保存为 CreateTable.php。在浏览器中查看此脚本,然后打开 phpMyAdmin,可以发现在MySQLDB数据库中,已经存在了表Users,其结构如图10-1所示。
图10-1 查看表Users的结构
2.执行查询语句
可以使用$conn->query()函数执行一个SELECT语句,并返回一个结果集,例如:
$results = $conn->query("SELECT * FROM Employees");
使用$results->fetch_row()函数可以获取结果集中的第一行记录,返回结果是一个数组,例如:
$row = $results->fetch_row();
通过使用while语句遍历$results中的所有记录,代码如下:
while($row = $results->fetch_row()) {
print_r($row);
}
【例10-3】 下面是使用mysqli函数遍历表Employees中记录的实例。
<?PHP
$conn = mysqli_connect("localhost", "root", "pass", "MySQLDB");
if (empty($conn)) {
die("mysqli_connect failed: " . mysqli_connect_error());
}
mysqli_query($conn, "SET NAMES gb2312");
//查询Employees中的员工数据
$sql = "SELECT EmpName, Title, Salary FROM Employees";
$results = $conn->query($sql);
//循环处理结果集中的记录
while($row = $results->fetch_row()) {
print($row[0] . " " . $row[1] . " " . $row[2] . "<BR>");
}
$results->free();
//关闭连接
mysqli_close($conn);
?>
程序的运行过程如下。
• 首先调用mysqli_connect()函数,创建到MySQLDB数据库的连接对象$conn。
• 如果$conn为空,则调用mysqli_connect_error()函数,输出错误信息。
• 调用 mysqli_query()函数,设置$conn 连接的字符集为 gb2312。注意,这条语句很重要,如果不使用此语句,则在显示中文时会出现乱码。
• 调用$conn->query()函数执行SELECT 语句,从表Employees 中读取字段信息,并将结果返回到$results中。
• 使用 while 语句循环处理结果集$results 中的记录,调用 fetch_row()函数可以获取一条记录,结果保存在数组变量$row中。在while语句中使用print语句,打开数组变量$row中的3个数组元素。
• 调用$results->free()函数,释放结果集对象。
• 调用mysqli_close()函数,释放连接对象。
假定此段代码保存为FetchData.php。如果没有使用mysqli_query()函数设置$conn连接的字符集,则浏览脚本的结果如图 10-2 所示。可以看到,结果中包含的中文都显示为??。正确使用mysqli_query()函数配置字符集后,浏览脚本的结果如图10-3所示。
图10-2 显示中文时出现乱码
图10-3 正确显示结果集
3.同时执行多个查询语句
使用mysqli_multi_query()函数或$conn->multi_query()函数可以一次执行多个SQL语句。调用$conn->store_result()函数可以获取到一个SELECT语句的结果集,使用$conn->next_result()函数可以获取到下一个结果集。在执行多个查询语句时,处理结果集需要使用两个循环语句,一个用于处理不同的结果集,另一个用于处理指定结果集中的记录。
【例10-4】 一个使用$conn->multi_query()函数同时执行两个 SELECT 语句,分别查询员工姓名和部门名称的示例程序。
<?php
$conn = mysqli_connect("localhost", "root", "pass", "MySQLDB");
if (empty($conn)) {
die("mysqli_connect failed: " . mysqli_connect_error());
}
mysqli_query($conn, "SET NAMES gb2312");
$query = "SELECT EmpName FROM Employees;";
$query .= " SELECT DepName FROM Departments;";
if ($conn->multi_query($query)) {
do {
if ($result = $conn->store_result()) {
while ($row = $result->fetch_row()) {
echo($row[0] . "<br>");
}
$result->close();
}
} while ($conn->next_result());
}
$conn->close();
?>
程序的运行过程如下。
• 首先调用mysqli_connect()函数,创建到MySQLDB数据库的连接对象$conn。
• 如果$conn为空,则调用mysqli_connect_error()函数,输出错误信息。
• 调用mysqli_query()函数,设置$conn连接的字符集为utf8。注意,这条语句很重要,如果不使用此语句,则在显示中文时会出现乱码。
• 设置变量$query的值为两个SELECT语句,分别从表Employees和表Departments中获取数据。
• 调用$conn->multi_query()函数,执行变量$query中保存的两个SELECT语句。
• 使用 while 语句处理不同的结果集,调用$conn->store_result()函数获取当前的结果集,调用$conn->next_result()函数移动至下一个结果集。
• 使用 while 语句循环处理结果集$results 中的记录,调用fetch_row()函数可以获取一条记录,结果保存在数组变量$row中。在while语句中使用echo()函数显示数组变量$row中的元素。
• 调用$results->free()函数,释放结果集对象。
• 调用mysqli_close()函数,释放连接对象。
假定此段代码保存为 multi-query.php,浏览脚本的结果如图10-4所示。
图10-4 例10-4的运行结果
可以看到,在页面中显示了所有员工姓名和部门名称。
10.1.3 分页显示结果集
如果在网页中显示的数据量过大,会导致网页结构变形,所以绝大多数网页都采用分页显示模式。分页显示就是指定每页可以显示的记录数量,并通过单击“第一页”按钮、“上一页”按钮、“下一页”按钮和“最后一页”按钮等翻页链接打开其他页面。
要实现分页显示,需要解决下面的问题。
1.获取结果集中的记录数
可以在SELECT语句中使用COUNT()函数获取结果集中的记录数量,代码如下:
SELECT COUNT(1) FROM 表名
假定获取记录数量保存在变量$RecordCount中。
2.设置每页显示记录的数量
假定使用变量$PageSize来保存每页显示记录的数量,它的值由用户根据需要自行设置,可以直接通过赋值语句来实现。例如,设置每页显示20条记录,可以使用下面的语句:
$PageSize = 20;
3.获取总页面数量
可以通过$RecordCount和$PageSize两个数据计算得到总页面数量$PageCount,方法如下:
if( $RecordCount ){
//如果记录总数量小于每页显示的记录数量,则只有一页
if( $RecordCount < $PageSize ){
$PageCount = 1;
}
//取记录总数量不能整除每页显示记录的数量,则页数等于总记录数量除以每页显示记录数量的结果取整再加1
if( $RecordCount % $PageSize ){
$PageCount = (int)($RecordCount / $PageSize) + 1;
}
else { //如果没有余数,则页数等于总记录数量除以每页显示记录的数量
$PageCount = $RecordCount / $PageSize;
}
}
else{ //如果结果集中没有记录,则页数为0
$PageCount = 0;
}
计算方法描述如下。
• 如果结果集中没有记录,则$PageCount等于0。
• 如果结果集中记录的数量$RecordCount 小于页面中显示的记录数量$PageSize,则页面数量$PageCount等于1。
• 如果结果集中记录的数量$RecordCount 是$PageSize 的整数倍,则$PageCount 等于$RecordCount除以$PageSize的结果。
• 如果结果集中记录的数量$RecordCount 不是$PageSize 的整数倍,则$PageCount 等于$RecordCount除以$PageSize的结果取整后加1。
4.如何显示第n页中的记录
虽然使用 PageSize 属性可以控制每页显示的记录数,但是要显示那些记录呢?可以在SELECT语句中使用LIMIT子句指定查询记录的范围,其使用方法如下:
SELECT * FROM 表名 LIMIT 起始位置, 显示记录数量
例如,要获取第$Page页中的记录,可以使用下面的语句:
SELECT * FROM 表名 LIMIT ($Page-1) * $PageSize, $PageSize
5.如何通知脚本要显示的页码
可以通过传递参数的方式通知脚本程序显示的页码。假定分页显示记录的脚本为viewPage.php,传递参数的链接如下:
http://localhost/viewPage.php?page=2
参数page用来指定当前的页码。在viewPage.php中,使用下面的语句读取参数:
$page = $_GET['page'];
if($page <= 0)
$page = 1;
变量$page 中就保存了当前的页码。使用变量$page 还可以定义翻页链接。“第一页”链接的代码如下:
echo(" <a href=viewPage.php?page=1>第一页</a> ");
“上一页”链接的代码如下:
echo(" <a href=viewPage.php?page=" . ($page-1) . ">上一页</a> ");
“下一页”链接的代码如下:
echo(" <a href=viewPage.php?page=" . ($page+1) . ">下一页</a> ");
“最后一页”链接的代码如下:
echo(" <a href=viewPage.php?page=" . $PageCount . ">最后一页</a> ")
比较完美的网页程序中,还需要根据当前的页码对翻页链接进行控制。如果当前页码是 1,则取消“第一页”和“上一页”的链接;如果当前页码是最后一页,则取消“下一页”和“最后一页”的链接。
【例10-5】 下面是演示分页显示记录的完整代码:
<HTML>
<HEAD><TITLE>分页显示记录</TITLE>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</HEAD>
<BODY>
<?PHP
//获取当前页码
$page = $_GET['page'];
if($page == 0)
$page = 1;
$PageSize = 3; // 为了演示分页效果
//连接到数据库
$conn = mysqli_connect("localhost", "root", "pass", "MySQLDB");
if (empty($conn)) {
die("mysqli_connect failed: " . mysqli_connect_error());
}
//执行SELECT 语句,获取表Employees的记录总数
$sql = "SELECT COUNT(1) FROM Employees";
$results = $conn->query($sql);
$row = $results->fetch_row();
$RecordCount = $row[0];
//////////////
//计算总页数//
/////////////
if( $RecordCount ){
//如果记录总数量小于每页显示的记录数量,则只有一页
if( $RecordCount < $PageSize ){
$PageCount = 1;
}
//取记录总数量不能整除每页显示记录的数量,则页数等于总记录数量除以每页显示记录数量的结果取整再加1
if( $RecordCount % $PageSize ){
$PageCount = (int)($RecordCount / $PageSize) + 1;
}
else { //如果没有余数,则页数等于总记录数量除以每页显示记录的数量
$PageCount = $RecordCount / $PageSize;
}
}
else{ //如果结果集中没有记录,则页数为0
$PageCount = 0;
}
//设置中文字符集
mysqli_query($conn, "SET NAMES gb2312");
echo("<BR>当前页码:" . $page . "/" . $PageCount);
?>
<table width="449" border="1">
<tr>
<td>员工姓名</td>
<td>职务</td>
<td>工资</td>
</tr>
<?PHP
//循环显示当前页的记录
$sql ="SELECT EmpName, Title, Salary FROM Employees LIMIT " . ($page-1) *$PageSize . "," . $PageSize;
$results = $conn->query($sql);
while($row = $results->fetch_row()) {
echo("<tr>");
echo("<td>" . $row[0] . " </td>");
echo("<td>" . $row[1] . " </td>");
echo("<td>" . $row[2] . " </td>");
echo("</tr>");
}
//关闭连接
mysqli_close($conn);
//显示分页链接
if($page == 1)
echo("第一页");
else
echo(" <a href=viewPage.php?page=1>第一页</a> ");
//设置“上一页”链接
if($page == 1)
echo("上一页");
else
echo(" <a href=viewPage.php?page=" . ($page-1) . ">上一页</a> ");
//设置“下一页”链接
if($page == $PageCount)
echo("下一页");
else
echo(" <a href=viewPage.php?page=" . ($page+1) . ">下一页</a> ");
//设置“最后一页”链接
if($page == $PageCount)
echo("最后一页");
else
echo(" <a href=viewPage.php?page=" . $PageCount . ">最后一页</a> ")
?>
</table>
</BODY>
</HTML>
程序中添加了比较详细的注释,请读者参照理解。假定这段代码保存为 viewPage.php,查看第一页记录的界面如图10-5所示。
图10-5 例10-5的运行结果