兄弟连 PHP 的 MySqli 扩展库
PHP 可以通过三套扩展库,实现对 mysql 数据库的管理
1. mysql 扩展
2. mysqli 扩展
3. PDO 扩展,该扩展不仅可以处理 mysql,还可以处理其他各种数据库
PHP5 最主要的是将面向对象全面改写了,PHP5 包括以后新增加的功能都会以对象的形式,
所以 PHP5 里面新增加的 mysqli 扩展库也是一种面向对象对的技术(但 mysqli 也支持过程化的使用方式),
mysqli 扩展只能在 PHP5 或更高的环境使用,MySQL 数据库本身必须在 4.1.3 或更高的版本
因为 mysqli 支持面向对象编程,也支持过程化的方式,
所以手册上任何一个示例,都提供了两种方式“面向对象的方法”和“过程化”
https://www.php.net/manual/zh/book.mysqli.php
而且 mysqli 过程化的方式和之前很相似只不过多了一个 i
mysql(i)_connect()
mysql(i)_select_db()
mysql(i)_query()
mysqli 扩展 i 表示改进的意思
1. 功能增加了
2. 效率大大的增加
3. 更稳定
window 下安装 mysqli 扩展库
1. 首先打开安装扩展的目录 D:\xampp\php\ext\
目录下有很多 PHP 扩展的功能,每个扩展就是一套库,比如 php_gd2.dll
如果看到一个 php_mysqli.dll 文件就是有这个扩展了
2. 然后开启 myqli 这个扩展库
在打开 PHP 配置文件 D:\xampp\php\php.ini
;extension=mysqli 把前面的分号去掉
3. 重启 apche 服务器,然后通过 phpinfo() 查看一下 mysqli 扩展
mysqli 扩展中给我们提供了三个类(按照功能区分)
| 类名 | 作用 | |
| mysqli() | 和连接有关的类 | 主要控制 PHP 和 mysql 数据之间对链接、选择数据库、向 mysql 数据库服务器发送 sql 语句,以及设置字符集等等 |
| mysqli_result() | 处理查询所返回的结果集 | 结果集就是用 select 语句从数据库中查询出来的,我们可以从结果集里面获取到记录信息、字段信息 |
| 通过上面 1 和 2 两个类,就可以完成之前过程化的 mysql 扩展的功能,而且效率更高、更稳定 下面第三个是 mysqli 新加的功能,通常叫预处理类 | ||
| mysqli_stmt() | 预处理类(后面重点介绍) | 表达了一个准备好对语句 |
为了便于学习,创建一个商品数据表
create database shopDB charset utf8; use shopDB; CREATE TABLE `products` ( `id` mediumint unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '0', `price` varchar(50) NOT NULL DEFAULT '0', `num` varchar(50) NOT NULL DEFAULT '0', `detail` varchar(500) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; truncate table products;
处理数据都离不开下面几个步骤
1. 链接数据库
2. 选择数据库
3. 执行查询语句
4. 处理结果集
一、连接数据库
使用构造方法 mysqli() 连接数据库,成功返回一个 mysqli 对象
1. 主机地址
2. 用户名
3. 密码
4. 数据库
5. 端口(可选)
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306');
var_dump($mysqli); // object(mysqli)#1 (18) { ... }如果链接失败也返回一个 mysqli 对象,对象里面有两个属性来处理失败
1. connect_errno 属性返回错误码,链接成功返回 0,失败返回 1045
2. connect_error 属性返回错误信息
// 符号@屏蔽系统的警告
$mysqli = @new mysqli('localhost', 'root', '错误密码', 'shopDB', '3306');
// var_dump($mysqli); // object(mysqli)#1 (3) { ... } 返回的对象里提供来处理链接失败的两个属性
if($mysqli->connect_errno){
echo $mysqli->connect_errno; // 1045
echo $mysqli->connect_error; // Access denied for user 'root'@'localhost' (using password: YES)
$mysqli = null; // 把mysqli对象赋值为null或false
exit; // 退出程序
}
echo '连接数据库成功';
$mysqli->close();error_reporting(0) 不用 @ 也可以屏蔽系统警告
高老师用了二个面向过程化的函数处理链接失败
if(mysqli_connect_errno()){
echo '连接失败';
echo mysqli_connect_error();
$mysqli = null; // 把mysqli对象赋值为null或false
exit;
}如果连接成功后,没有选择数据库,
select_db('dbname') 可以选择或切换数据库
$mysqli = new mysqli('localhost', 'root', ''); // 没有写第四个参数
if($mysqli->connect_errno) {
echo $mysqli->connect_errno;
echo $mysqli->connect_error;
exit;
}
$mysqli->select_db('dbshop'); // 选择数据库
echo '连接成功';
$mysqli->close();还有一种方式连接数据库
1. 初始化 mysqli 对象 mysqli_init() ,它直接返回一个 mysqli 对象
2. 用返回对象里面的方法 real_connect() 连接数据库
3. options( in option, mixed value ) 可以设置选项优化
$mysqli = mysqli_init();
// options( in option, mixed value ); 详见 https://www.php.net/manual/zh/mysqli.options.php
$mysqli->real_connect('127.0.0.1', 'root', '', 'shopDB');
if($mysqli->connect_errno){
echo $mysqli->connect_error;
exit;
}
echo '链接成功';
$mysqli->close();链接上数据库后,可以调用返回对象 $mysqli 里的 close() 方法关闭(断开)打开的连接,
在关闭之前可以任意执行 mysqli 对象里面的东西,比如查询语句、获取一些服务器的信息
比如获取服务器端、客户端信息的方法和属性
1. character_set_name() 获取当前字符集(mysql 用的什么字符集)
2. get_client_info() 获取 mysql 客户端的信息
3. host_info 主机信息
4. protocol_version 协议的版本
5. server_info 服务器的信息
6. server_version 服务器的版本
7. info 获取最近执行的查询信息
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306');
if($mysqli->connect_errno){
echo $mysqli->connect_error;
exit;
}
echo $mysqli->character_set_name().'<br/>'; // utf8mb4
echo $mysqli->get_client_info().'<br/>'; // mysqlnd 7.4.20
echo $mysqli->host_info.'<br/>'; // localhost via TCP/IP
echo $mysqli->protocol_version.'<br/>'; // 10
echo $mysqli->server_info.'<br/>'; // 5.5.5-10.4.19-MariaDB
echo $mysqli->server_version.'<br/>'; // 100419
echo $mysqli->info.'<br/>'; //
$mysqli->close();二、执行 sql 语句
执行 sql 语句有多种方式
1. query() 执行 sql 语句(最常用的)
2. prepare() 准备一个 sql
3. multi_query() 执行多个查询
sql 语句又分两种
1. 一种是 select 语句,它有结果集
2. 还有一种非 select 语句,会影响行数
query( string query, [, int resultmode] )
使用 query() 方法发送 sql 语句到数据库并且执行
1. 如果是非 select 语句返回 bool 类型,成功返回真,失败返回假
2. 如果是 select 语句返回结果集对象
1、判断 sql 语句是否有误
query() 方法执行非 select 语句返回 bool
1. 所以可以用 query() 方法返回的 $result 判断 sql 语句是否成功
2. 如果有 sql 语句有错误,通过 Mysqli 对象里面的两个属性获取错误信息,errno 获取错误号、error 获取错误信息
$mysqli = @new mysqli('localhost', 'root', '', 'shopDB', '3306');
if($mysqli->connect_errno) {
echo "数据连接错误" . $mysqli->connect_error;
exit;
}
$sql = "insert into products(id, name, price, num, detail)values(null, 'HUAWEI', '6000', '300', 'HarmonyOS系统')";
$result = $mysqli->query($sql);
// var_dump($result); // bool(true)
if(!$result){
echo "sql语句有误<br/>";
echo $mysqli->errno;
echo $mysqli->error;
exit;
}
$mysqli->close();记录 2 个提示的错误
字段写错了,提示 Unknown column 'xxx' in 'field list',未知的列 xxx 在字段列表里面
表名写错了,提示 Table 'shopdb.productsxxx' doesn't exist,表名 productsxxx 不存在
2、获取到影响的行数
非 select 语句执行成功会影响行数,影响行数的语句有
插入语句 insert
删除语句 detele
更新语句 updata
比如插入一次影响 1 个行数,通过属性 affected_rows 获取到影响的行数
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306');
$products = ['华为', '小米', '苹果', 'oppo', 'vivo'];
$detail = ['双卡双待', '4G', '快速充电', '无线充电', '硬件配置高', '像素高'];
$sql = "insert into products(id, name, price, num, detail)values(null, '".$products[rand(0, 4)]."', '".rand(10000, 1999)."', '".rand(200, 10)."', '".$detail[rand(0, 5)]."')";
$result = $mysqli->query($sql);
echo $mysqli->affected_rows; // 1
$mysqli->close();detele 删除语句影响行数
1. 第一次刷新,删除多行,显示影响多行,
2. 在刷新一次影响 0 条,sql 语句本身没有错,只是没有满足条件的记录而已
3. 所以判断影响的行数大于 0 的时候,是真正的删除成功,或真正修改成功了
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306');
$sql = "delete from products where id > '6'";
$result = $mysqli->query($sql);
if($mysqli->affected_rows > 0){
echo "删除语句成功,影响 $mysqli->affected_rows 行";
}else{
echo '没有行数被影响';
}
$mysqli->close();3、获取自动增长的 id
insert_id
两个表同时插入,第二个表要用到第一个表的 id
只有 insert 插入语句,而且表中有一列是自动增长的 ,才能获取到自动增长的 id
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306');
if ($mysqli->connect_errno) {
echo "Mysqli Link Error: $mysqli->connect_errno $mysqli->connect_error";
exit;
}
$sql = "insert into products(id, name, price, num, detail)values(null, 'HUAWEI', '6000', '300', 'HarmonyOS操作系统')";
$result = $mysqli->query($sql);
if(!$result){
echo "sql语句有误 $mysqli->errno | $mysqli->error";
exit;
}
echo "最后增长的ID ", $mysqli->insert_id; // 获取最后自动增长的id
$mysqli->close();三、处理结果集
mysqli 扩展的三个类中的 mysqli_result 是专门处理使用查询 select 语句获得的结果集
结果集主要处理有两方面
1. 处理记录,就是一条一条把记录读取出来
2. 处理字段信息,结果集中列(字段)信息,比如获取列名、列的属性
mysqli_result 结果集类里面方法
| 名称 | 作用 | 参数 |
| data_seek() | 移动记录的指针,指定从第几条数据开始获取数据 | data_seek(5) |
| fetch_array() | 获取记录信息,关联索引两种数组 | MYSQL_ASSOCI,MYSQLI_NUM,MYSQLI_BOTH 默认是第三个 |
| fetch_assoc() | 获取记录信息,关联数组的方式 | |
| fetch_object() | 获取记录信息,对象的形式 | |
| fetch_row() | 获取记录信息,索引数组的形式 | |
| free_result() | 释放结果集 | |
| close() | 释放结果集 | |
| field_seek() | 移动字段(列)的指针 | |
| fetch_field() | 获取列的信息,也是每次获一列,然后往下走一次 | |
| fetch_fields() | ||
| fetch_field_direct() |
mysqli_result 结果集类里面的属性
| 名称 | 作用 |
| current_field | 获取当前列的列号 |
| field_count | 获取结果集中的列数,有几个字段 |
| lengths | 返回当前列中字段的长度 |
| num_rows | 获取结果集中的行数,共有多少条数据 |
| type |
执行 select 查询语句,返回的是结果集,这里的结果集就是一个对象 object(mysqli_result)
header('Content-Type: text/html; charset=utf-8');
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
if ($mysqli->connect_errno) {
echo "数据库连接错误".$mysqli->connect_error;
exit;
}
$sql ="select * from products";
$result = $mysqli->query($sql); // 执行select语句返回的结果集是一个对象
var_dump($result); // object(mysqli_result)#2 (5) { ["current_field"]=> int(0) ["field_count"]=> int(5) ["lengths"]=> NULL ["num_rows"]=> int(69) ["type"]=> int(0) }
$result->close(); // 释放结果集
$mysqli->close();按过程化来说,结果集也是一种资源也需要释放,下面三个方法都可以释放的,用那个都可以
free()
close()
free_result()
1、处理记录信息
获取记录信息的四个方法
fetch_row() 返回索引数组
fetch_assoc() 返回关联数组,下标就是列名
fetch_array() 两个数组都返回,尽量不使用,因为取两个数组效率不是那么高
fetch_object() 返回对象
每执行一次 fetch_assoc(),
就会从结果集中取出当前一条记录(默认当前记录就是第一行,可以使用 data_seek(5) 方法指定,5 表示默认从第五行记录开始取)
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
if ($mysqli->connect_errno) {
echo "Mysqli Link Error: $mysqli->connect_error";
exit;
}
$sql ="select * from products";
$result = $mysqli->query($sql);
if(!$result){
echo "Sql语句错误: $mysqli->errno $mysqli->error";
exit;
}
$assoc = $result->fetch_assoc(); // 每执行一次从结果集中取出当前一条记录
print_r($assoc); // Array ( [id] => 1 [name] => vivo [price] => 7008 [num] => 48 [detail] => 快速充电 )
$result->close();
$mysqli->close();循环取出数组
1. 每循环一次换一行,指针指向下一行,,
2. 循环执行取出下一行,正常的情况下返回数组,数组会当成 true 来处理
3. 当结果集中没有记录获取不到的时候返回 false 的时候退出循环
header('Content-Type: text/html; charset=utf-8');
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
if ($mysqli->connect_errno) {
echo "Mysqli Link Error: $mysqli->connect_error";
exit;
}
$sql ="select * from products";
$result = $mysqli->query($sql);
if(!$result){
echo "Sql语句错误: $mysqli->errno $mysqli->error";
exit;
}
// 每循环一次换一行,当最后一条获取不到时返回false退出循环,正常的情况下返回数组,数组会当成true来处理
while($rows = $result->fetch_assoc()){
print_r($rows);
echo "<br/>";
}
$result->close();
$mysqli->close();用 table 表格的形式打印出来
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
if ($mysqli->connect_errno) {
echo "Mysqli Link Error: $mysqli->connect_errno $mysqli->connect_error";
exit;
}
$result = $mysqli->query("select * from products");
$result->data_seek(50); // 指定从结果集里面移动指针到第50行开始取数据
if(!$result){
echo "Sql语句错误: $mysqli->errno $mysqli->error";
exit;
}
echo '<table border="1" align="center" width="900">';
while($rows = $result->fetch_assoc()){
echo '<tr>';
// $rows是数组包含每一列的信息,可以用foreach便利数组
// foreach($rows as $val){
// echo "<td>{$val}</td>";
// }
// 也可以一行一行的写出每个单元
echo "<td>{$rows['id']}</td>
<td>{$rows['name']}</td>
<td>{$rows['price']}</td>
<td>{$rows['detail']}</td>";
echo '</tr>';
}
echo '</table>';
$result->close();
$mysqli->close();结果集中的行数和列数
num_rows 属性,获取结果集中共有多少条数据(多少行)
field_count 属性,获取结果集中的列数,就是有几个字段(这个和下面获自段信息有点联系)
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
if ($mysqli->connect_errno) {
echo "Mysqli Link Error: $mysqli->connect_error";
exit;
}
$sql ="select id, name from products where id < 50"; // 查询2个字段设置一个where条件限制,会影响取到的行数和列数
$result = $mysqli->query($sql);
$rows = $result->num_rows; // 获取结果集中的行数
$cols = $result->field_count; // 获取结果集中的列数(列的个数和下面)
echo "数据表中有{$rows}行,{$cols}列";
$result->close(); // 关闭结果集
$mysqli->close();2、处理字段信息
fetch_field() 获取当前列信息
1. 每次获取完一列,然后指针往下走一次
2. 返回来的是一个对象,通过这个对象我们能获取
| 属性名 | |
| name | 列名 |
| orgname | 列的原名,因为表和列都可以起别名 |
| table | 表名 |
| orgtable | 原表名,因为表和列都可以起别名 |
| max_length | 最大长度,字段值的最大列的长度 |
| length | 长度 |
| charsetnr | 字符集 |
| flags | |
| type | 类型 |
| decimals |
name 属性获取列的名称,
max_length 属性列最大长度
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
$result = $mysqli->query("select id cid, name shopname, price, num, detail from products"); // 给列起别名
echo '<table border="1" align="center" width="900">';
echo '<tr>';
// 一共有5列自动循环五列,到最后一列返回false就结束循环了
while($field = $result->fetch_field()){
echo "<th>{$field->name}[{$field->max_length}]</th>"; // 返回来一个$field对象,在对象里name和max_length获取列的名称和列长度
}
echo '</tr>';
while($rows = $result->fetch_assoc()){
echo '<tr>';
foreach($rows as $col){
echo "<td>{$col}</td>";
}
echo '</tr>';
}
echo '</table>';
$mysqli->close();上面的 data_seek() 方法可以移动记录的指针,
field_seek() 方法可以移动字段的指针,field_seek(2) 从第二个字段开始取
fetch_fields() 方法
1. 一次性把所有列全取过来了,然后形成一个数组
2. 数组里面每一个成员,就是每一个列的对象
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
$sql = "select id cid, name shopname, price, num, detail from products"; // 给列起别名
$result = $mysqli->query($sql);
echo '<table border="1" align="center" width="900">';
echo '<tr>';
$fields = $result->fetch_fields(); // 一次性把列全取出来
foreach($fields as $col){
echo "<th>{$col->name}[{$col->max_length}]</th>";
}
echo '</tr>';
while($rows = $result->fetch_assoc()){
echo '<tr>';
foreach($rows as $col){
echo "<td>{$col}</td>";
}
echo '</tr>';
}
echo '</table>';
$mysqli->close();lengths 结果集对象属性,跟之前 max_length 属性获取列的最大长度一样,只过不返回的是单个的每一个列长度
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
$sql = "select * from products";
$result = $mysqli->query($sql);
echo '<table border="1" align="center" width="900">';
while($rows = $result->fetch_assoc()){
echo "<tr>
<td>{$rows['id']} [{$result->lengths[0]}]</td>
<td>{$rows['name']} [{$result->lengths[1]}]</td>
<td>{$rows['price']} [{$result->lengths[2]}]</td>
<td>{$rows['num']} [{$result->lengths[3]}]</td>
<td>{$rows['detail']}[{$result->lengths[4]}]</td>
</tr>";
}
echo '</table>';
$mysqli->close();current_field 是结果集 $result 对象里面属性(不是 $fieild 里面的属性),获取当前列的列号
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
$sql = "select * from products";
$result = $mysqli->query($sql);
echo '<table border="1" align="center" width="900">';
echo '<tr>';
while($field = $result->fetch_field()){
// current_field属性是结果集$result里面的属性,作用是返回当前列的列号
echo "<th>{$result->current_field}_{$field->name} [{$field->max_length}]</th>";
}
echo '</tr>';
while($rows = $result->fetch_assoc()){
echo '<tr>';
foreach($rows as $col){
echo "<td>{$col}</td>";
}
echo '</tr>';
}
echo '</table>';
$mysqli->close();怎么获取 主键 和 唯一索引?
desc products 查看表结构的 sql 语句
可以看到那个是主键,
那个是唯一索引,
那个字段是否为空,
所以获取表的详细信息,借助于sql语句 desc products 就可以了
$mysqli = new mysqli("localhost", "root", "", "shopdb", "3306");
$result = $mysqli->query("desc products"); // 通过sql语句获取的表信息,也是表格的形式
echo '<table border="1" align="center" width="900">';
echo '<tr>';
while($field = $result->fetch_field()){
echo "<th>{$field->name}</th>";
}
echo '</tr>';
while($rows = $result->fetch_assoc()){
echo '<tr>';
foreach($rows as $val){
echo "<td>{$val}</td>";
}
echo '</tr>';
}
echo '</table>';
$mysqli->close();总结,
获取结果集中列和行的信息
field_count
current_field
lengths
field_seek()
fetch_field()
fetch_fields()
