PHP 的 MySqli 扩展库
php 可以通过三套扩展库,实现对 mysql 数据库的管理
1. mysql 扩展
2. mysqli 扩展
3. PDO 扩展,该扩展不仅可以处理mysql,还可以处理其他各种数据库
本节课讲解 mysqli 扩展库
1. PHP5.0 最主要的是将面向对象全面改写了,和 PHP4 比 PHP5 以后新增加的功能,都会以对象的形式增加
2. mysqli 扩展库了是 PHP5 里面新增加的,所以它也是一种面向对象对的技术,但也支持过程化的使用方式
i 表示改进的意思,1).功能增加了,2).效率大大的增加,3).更稳定
3. mysqli 扩展只能在 PHP5.0 或更高的环境使用,MySQL 4.1 或更高的版本
window 下安装 mysqli 扩展库
1. 首先打开安装扩展的目录 D:\xampp\php\ext\,目录下有很多 PHP 扩展的功能,
每个扩展就是一套库,比如 php_gd2.dll
如果看到一个 php_mysqli.dll 文件就是有这个库了
2. 打开 PHP 配置文件 D:\xampp\php\php.ini 开启 myqli 这个扩展库
;extension=mysqli 把前面的分号去掉
3. 重启 apche 服务器,然后通过 phpinfo 查看
按照功能区分 mysqli 扩展提供了三个类
1. MySQLi 和连接有关的类
主要控制 PHP 和 mysql 数据之间对链接、选择数据库、向 mysql 数据库服务器发生sql语句,以及设置字符集等等
2. Mysqli_result 处理结果集类
结果集就是用 select 语句从数据库中查询出来的,我们可以从结果集里面获取到记录信息、字段信息
以上两个类就可以完成前面过程化的 mysql 扩展的功能,而且效率更高、更稳定
第三个类就是 mysqli 新加的功能,我们通常叫预处理类
3. Mysqli_stmt 预处理类(后面重点介绍)
表达了一个准备好对语句
因为 mysqli 支持面向对象编程,也支持过程化的方式,
所以手册上任何一个示例,都提供了“面向对象的方法”和“过程化”的两种方式
https://www.php.net/manual/zh/book.mysqli.php
而且 mysqli 过程化的方式和之前很相似只不过多了一个 i
mysql(i)_connect()
mysql(i)_select_db()
mysql(i)_query()
为了便于测试,创建一个商品数据表
create database shopDB charset utf8; use shopDB; CREATE TABLE `products` ( `id` mediumint unsigned NOT NULL AUTO_INCREMENT, `ishow` tinyint unsigned NOT NULL DEFAULT '0', `name` varchar(50) NOT NULL DEFAULT '0', `phone` varchar(50) NOT NULL DEFAULT '0', `intro` varchar(1500) NOT NULL DEFAULT '0', `time` varchar(50) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; 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;
一、操作 MySQL 数据库
处理数据都离不开下面几个步骤
1. 链接数据库
2. 选择数据库
3. 执行查询语句
4. 处理结果集
1、连接数据库
通常使用构造方法 mysqli() 连接数据库,链接成功返回 mysqli 对象
$mysqli = new mysqli('localhost', 'root', '', 'shopDB', '3306'); // 主机地址, 用户名, 密码, 数据库, 端口(可选) var_dump($mysqli); // object(mysqli)#1 (18) { ... }
如果链接失败返回 mysqli 对象里面有两个属性
connect_errno 属性,返回错误码,链接成功返回 0,失败返回 1045
connect_error 属性,返回错误信息
error_reporting(0); // 屏蔽系统的警告 $mysqli = new mysqli('localhost', 'root', '错误密码', 'shopDB', '3306'); // var_dump($mysqli); // object(mysqli)#1 (18) { ... } if ($mysqli->connect_errno) { echo $mysqli->connect_errno; // 1045 echo $mysqli->connect_error; // Access denied for user 'root'@'localhost' (using password: YES) exit; } echo '连接数据库成功'; $mysqli->close(); // 关闭打开的连接
老师用了2个面向过程化的函数
$mysqli = @new mysqli('localhost', 'root', '错误密码', 'shopDB', '3306'); if(mysqli_connect_errno()){ echo '连接失败'; echo mysqli_connect_error(); $mysqli = null; // 把mysqli对象赋值为null或false exit; } echo '连接数据库成功'; $mysqli->close();
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();
还有一种 mysqli_init(void) 连接数据库的方式
mysqli_init 返回一个 mysqli 对象
real_connect 连接数据库
$mysqli = mysqli_init(); $mysqli->real_connect('127.0.0.1', 'root', '', 'shopDB'); if($mysqli->connect_errno){ echo $mysqli->connect_error; exit; } echo '链接成功'; $mysqli->close();
options( in option, mixed value )
可以设置选项优化
https://www.php.net/manual/zh/mysqli.options.php
2、获取服务器端、客户端信息的方法和属性
character_set_name() 获取当前字符集(mysql 用的什么字符集)
get_client_info() 获取 mysql 客户端的信息
host_info 主机信息
protocol_version 协议的版本
server_info 服务器的信息
server_version 服务器的版本
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();
3、执行 sql 语句
执行 sql 语句的方式有多种
1. query() 执行sql语句(最常用的)
2. prepare() 准备执行一个sql查询语句
3. multi_query() 执行多个查询语句
sql 语句又分两种
1. 一种是 select 语句有结果集
2. 还有一种非 select 语句,会影响行数
query( string query, [, int resultmode] )
使用 mysqi 里面的 queyr() 方法发送 sql 语句到数据库并且执行
1. 如果是非 select 语句返回 bool 类型,成功返回真,失败返回假
2. 如果是 select 语句返回结果集对象
这里是非 select 语句,
1. 非 select 语句返回 bool 类型,所以可以用返回 !$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 不存在
非 select 语句执行成功,
会影响的行数,通过 affected_rows 属性获取到影响的行数
什么语句会影响行数
插入语句 insert
删除语句 detele
更新语句 updata
插入一次影响 1 个行数
$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();
删除语句影响行数
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();
!$result 是判断 sql 语句是否有误
affected_rows 属性是判断有没有行数被影响,要经常用到这个属性
insert_id
只有插入语句,而且表中有一列是自动增长的 ,才能获取到自动增长的 id
因为目的是让我们完成,两个表同时插入,第二个表要用到第一个表的 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; } if($mysqli->affected_rows > 0){ echo "影响 $mysqli->affected_rows 行<br/>"; } 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() |
属性
名称 | 作用 |
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();
循环取出数组
每次取出一行,指针指向下一行,下次执行取出下一行,
每循环一次换一行,当结果集中没有记录获取不到的时候返回 false 的时候退出循环,正常的情况下返回数组,数组会当成 true 来处理
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()