PHP中的PDO操作学习(四)查询结构集
关于 PDO 的最后一篇文章,我们就以查询结果集的操作为结束。在数据库的操作中,查询往往占的比例非常高。在日常的开发中,大部分的业务都是读多写少型的业务,所以掌握好查询相关的操作是我们学习的重要内容。和 mysqli 一样,PDO 对于查询的支持也是非常方便快捷的,通过几个函数就可以非常方便高效地操作各种查询语句。
在使用预处理语句的情况下,我们使用 execute() 执行之后,查询的结果集就会保存在 PDOStatement 对象中。对于数据的操作就转移到了 PHP 的对象中,所以我们需要 PDOStatement 的一些方法来获得结果集的内容。
fetch() 方法
通过 fetch() 方法,获得的是查询结果集的下一行。
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$row = $stmt->fetch();
print_r($row);
// Array
// (
// [id] => 1
// [0] => 1
// [username] => aaa
// [1] => aaa
// [password] => aaa
// [2] => aaa
// [salt] => aaa
// [3] => aaa
// )
从返回的结果来看,我们没有给 PDO 对象指定 PDO::ATTR_DEFAULT_FETCH_MODE 属性,所以它是返回的默认的 PDO::FETCH_BOTH 格式,也就是字段名和下标同时存在的。其实这个方法可以直接指定我们需要的 FETCH_STYLE 。
结果集类型指定
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
// Array
// (
// [id] => 2
// [username] => bbb
// [password] => bbb
// [salt] => 123
// )
$row = $stmt->fetch(PDO::FETCH_LAZY);
print_r($row);
// PDORow Object
// (
// [queryString] => select * from zyblog_test_user
// [id] => 3
// [username] => ccc
// [password] => bbb
// [salt] => c3
// )
$row = $stmt->fetch(PDO::FETCH_OBJ);
print_r($row);
// stdClass Object
// (
// [id] => 4
// [username] => ccc
// [password] => bbb
// [salt] => c3
// )
和指定 PDO 对象的 PDO::ATTR_DEFAULT_FETCH_MODE 一样。使用 fetch() 方法时直接将需要的返回结果类型参数指定到方法的第一个参数,就实现了 FETCH_STYLE 的指定。具体支持的格式和之前讲过的 PDO 对象的 PDO::ATTR_DEFAULT_FETCH_MODE 属性是完全一样的,大家可以自行查阅。
获取全部数据
从代码和定义中可以看出,fetch() 方法是获取当前数据集的下一行数据,就像数据库的游标操作一样。所以,我们可以通过循环 fetch() 来对结果集进行遍历,从而获得所有的结果集数据。
while($row = $stmt->fetch()){
print_r($row);
}
// Array
// (
// [id] => 2
// [0] => 2
// [username] => bbb
// [1] => bbb
// [password] => bbb
// [2] => bbb
// [salt] => 123
// [3] => 123
// )
// ……
MySQL 不支持游标
上文中提到了游标操作,PDO 扩展是支持游标的,但是需要注意的是,MySQL 扩展并不支持这个操作。所以我们使用游标相关的属性对于 MySQL 库是没有效果的。
$stmt = $pdo->prepare("select * from zyblog_test_user", [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT);
print_r($row);
// Array
// (
// [id] => 1
// [username] => aaa
// [password] => aaa
// [salt] => aaa
// )
$stmt = $pdo->prepare("select * from zyblog_test_user", [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST);
print_r($row);
// Array
// (
// [id] => 1
// [username] => aaa
// [password] => aaa
// [salt] => aaa
// )
如果是支持游标操作的数据库及扩展的话,上面代码中的 fetch() 的第二个参数指定后,获取的结果是会不同的。PDO::FETCH_ORI_NEXT 是获取游标的下一条数据,而 PDO::FETCH_ORI_LAST 是获取游标的最后一条数据。但是在我们对 MySQL 的测试中,它们并没有任何效果,依然是获取结果集的下一条数据。
fetchAll() 方法
通过 fetch() 方法,我们可以获得结果集中的全部数据,不过还是需要一个循环才能进行遍历,多少还是有点麻烦。其实,PDO 早就为我们准备好了另一个方法,fetchAll() 就是返回一个包含结果集中所有行的数组。
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll();
print_r($list);
// Array
// (
// [0] => Array
// (
// [id] => 1
// [0] => 1
// [username] => aaa
// [1] => aaa
// [password] => aaa
// [2] => aaa
// [salt] => aaa
// [3] => aaa
// )
// [1] => Array
// (
// [id] => 2
// [0] => 2
// [username] => bbb
// [1] => bbb
// [password] => bbb
// [2] => bbb
// [salt] => 123
// [3] => 123
// )
// )
fetchAll() 就是在内部使用了 fetch() 帮我们遍历了一次结果集并且赋值到了一个数组中。所以我们如果在不重新 execute() 情况下再次调用 fetchAll() 的话,获取的就是空的数据。因为游标已经到底了。
$list = $stmt->fetchAll();
print_r($list);
// Array
// (
// )
它同样支持指定 FETCH_STYLE ,也和 fetch() 方法一样,直接将需要的类型常量赋值给第一个参数就可以了。
// PDO::FETCH_ASSOC
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($list);
// Array
// (
// [0] => Array
// (
// [id] => 1
// [username] => aaa
// [password] => aaa
// [salt] => aaa
// )
// [1] => Array
// (
// [id] => 2
// [username] => bbb
// [password] => bbb
// [salt] => 123
// )
// )
// PDO::FETCH_COLUMN
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
print_r($list);
// Array
// (
// [0] => aaa
// [1] => bbb
// )
// PDO::FETCH_CLASS
class User{
function __construct($a){
echo $a, PHP_EOL;
}
}
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_CLASS, 'User', ['FetchAll User']);
print_r($list);
// FetchAll User
// FetchAll User
// Array
// (
// [0] => User Object
// (
// [id] => 1
// [username] => aaa
// [password] => aaa
// [salt] => aaa
// )
// [1] => User Object
// (
// [id] => 2
// [username] => bbb
// [password] => bbb
// [salt] => 123
// )
// )
是不是非常熟悉了,这里就不多讲了,关于 FETCH_STYLE 的类型指定已经说过很多遍了,它的用法和 fetch() 以及 PDO 对象中的 query() 方法都是差不多的。不过它还支持一种以回调方式调用一个方法的形式来获得数据集。
function getValue(){
print_r(func_get_args());
}
// Array
// (
// [0] => 1
// [1] => aaa
// [2] => aaa
// [3] => aaa
// )
// Array
// (
// [0] => 2
// [1] => bbb
// [2] => bbb
// [3] => 123
// )
$stmt = $pdo->prepare("select * from zyblog_test_user limit 2");
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_FUNC, 'getValue');
print_r($list);
// Array
// (
// [0] =>
// [1] =>
// )
在这段代码中,我们使用的是 PDO::FETCH_FUNC ,第二个参数是一个方法名称。这样每一条结构集都会在遍历的时候作为方法的参数去调用指定的这个方法,我们通过 func_get_args() 就可以获取到这些参数内容。在这段代码中,结果集并不会通过 fetchAll() 方法的返回值赋值给 $list 变量了。因为数据都已经传递给了指定的 getValue() 方法了。
fetchColumn() 方法
在上面的测试代码中,我们使用过 PDO::FETCH_COLUMN 来获取结果集的某一列数据。这样写没什么问题,但是还有更方便的方式,也就是 PDOStatment 直接为我们提供的一个 fetchColumn() 方法。它就相当于是默认的在方法内部指定了 PDO::FETCH_COLUMN ,并且只需要一个参数就是列的下标。
需要注意的是,它的返回是下一行的指定列值,也就是说,它在底层是调用的 fetch() 方法。如果要获取结果集中所有指定列的内容,我们还需要通过和 fetch() 的遍历方式一样的方法来遍历结果集。
// fetchColumn
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$column = $stmt->fetchColumn(2);
echo $column, PHP_EOL;
// aaa
$column = $stmt->fetchColumn(3);
echo $column, PHP_EOL;
// 123
fetchObject() 方法
fetchObject() 就不用多解释了,它和 fetchColumn() 是类似的,只是返回的是下一行数据的对象格式。同样的,它也是可以传递构造参数的,这点和 PDO 对象的 query() 中指定的 PDO::FETCH_CLASS 格式的使用是一样的。我们在第一篇文章中就有讲解。
// fetchObject
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$user = $stmt->fetchObject('User', ['FetchObject User']);
print_r($user);
// FetchObject User
// User Object
// (
// [id] => 1
// [username] => aaa
// [password] => aaa
// [salt] => aaa
// )
rowCount() 返回查询结果数量
要获得查询的结果集行数就需要我们的 rowCount() 方法了。数据库中不管是查询还是增、删、改操作,都会返回语句执行结果,也就是受影响的行数。这些信息都是通过 rowCount() 这个方法获得的。
查询语句返回行数
需要注意的是,在查询语句中,有些数据是可能返回此语句的行数的。但这种方式不能保证对所有数据有效,且对可移植的应用更不要依赖这种方式。我们如果需要知道当前查询结果的数量,还是通过遍历 fetch() 或者通过 count(fetchAll()) 来根据真实查询到的结果集数量确定这一次查询的真实行数。
其实它就像是 PDO 对象的 exec() 方法所返回的数据。在不使用预处理语句的情况下,直接使用 PDO 的 exec() 方法执行 SQL 语句后,返回的也是语句执行后受影响的行数。
$stmt = $pdo->prepare("select * from zyblog_test_user");
$stmt->execute();
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL;
// 41
增、删、改语句返回受影响的行数
$stmt = $pdo->prepare("insert into zyblog_test_user(username, password, salt) values(?, ?, ?)");
$stmt->execute(['kkk','666','k6']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 1
$id = $pdo->lastInsertId();
echo $rowCount, PHP_EOL; // 1
$stmt = $pdo->prepare("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 25
$stmt = $pdo->prepare("update zyblog_test_user set username=? where username = ?");
$stmt->execute(['ccc','cccc']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 0
$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$stmt->execute(['ddd']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 11
$stmt = $pdo->prepare("delete from zyblog_test_user where username = ?");
$stmt->execute(['ddd']);
$rowCount = $stmt->rowCount();
echo $rowCount, PHP_EOL; // 0
更新和删除操作在数据不存在、没有更新、没有删除的情况下都返回的是 0 。这一点我们也在 PDO 相关的第一篇文章中就说过了,对于业务来说,这种更新或删除到底算是成功还是失败呢?还是大家根据自己的实际业务情况来确定吧!
总结
关于 PDO 和 PDOStatement 相关的内容就学习到这里了。我们完整地梳理了一遍它们两个所有的方法,也都进行了相关的测试。大家在日常使用中可能接触到的并不多,框架都已经为我们封装好了。不过对于学习来说,平常的小测试、小调试完全可以自己手写来加深记忆和理解。在深入理解了这些扩展类的使用方法后,反过来又能帮助我们更加的清楚框架是如何去封装它们的。总之,学习就是不断的从高层到底层,再从底层返回高层,循环往复,才能更加的得心应手。
测试代码:
参考文档:
https://www.php.net/manual/zh/book.pdo.php
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP中的PDO操作学习(四)查询结构集的更多相关文章
- PHP中的PDO操作学习(三)预处理类及绑定数据
要说 PDO 中最强大的功能,除了为不同的数据库提供了统一的接口之外,更重要的就是它的预处理能力,也就是 PDOStatement 所提供的功能.因为它的存在,才让我们可以安心地去使用而不用操心 SQ ...
- PHP中的PDO操作学习(二)预处理语句及事务
今天这篇文章,我们来简单的学习一下 PDO 中的预处理语句以及事务的使用,它们都是在 PDO 对象下的操作,而且并不复杂,简单的应用都能很容易地实现.只不过大部分情况下,大家都在使用框架,手写的机会非 ...
- PHP中使用PDO操作事务的一些小测试
关于事务的问题,我们就不多解释了,以后在学习 MySQL 的相关内容时再深入的了解.今天我们主要是对 PDO 中操作事务的一些小测试,或许能发现一些比较好玩的内容. 在 MyISAM 上使用事务会怎么 ...
- 彻底理解Oracle中的集合操作与复合查询
--Oracle中的复合查询 复合查询:包含集合运算(操作)的查询 常见的集合操作有: union: 两个查询的并集(无重复行.按第一个查询的第一列升序排序) union all:两个查询的并集(有重 ...
- Ibatis.Net 数据库操作学习(四)
一.查询select 还记得第一篇示例中是如何读出数据库里3条数据的吗?就是调用了一个QueryForList方法,从方法名就知道,查询返回列表. 1.QueryForList 返回List< ...
- Mysql高级操作学习笔记:索引结构、树的区别、索引优缺点、创建索引原则(我们对哪种数据创建索引)、索引分类、Sql性能分析、索引使用、索引失效、索引设计原则
Mysql高级操作 索引概述: 索引是高效获取数据的数据结构 索引结构: B+Tree() Hash(不支持范围查询,精准匹配效率极高) 树的区别: 二叉树:可能产生不平衡,顺序数据可能会出现链表结构 ...
- MyBatis 中实现SQL语句中in的操作 (11)
MyBatis 中实现SQL语句中in的操作 概括:应用myBatis实现SQL查询中IN的操作 1.数据库结构及其数据 2.mapper.xml文件 <?xml version="1 ...
- PHP中的PDO对象操作学习(一)初始化PDO及原始SQL语句操作
PDO 已经是 PHP 中操作数据库事实上的标准.包括现在的框架和各种类库,都是以 PDO 作为数据库的连接方式.基本上只有我们自己在写简单的测试代码或者小的功能时会使用 mysqli 来操作数据库. ...
- PHP中的MySQLi扩展学习(五)MySQLI_STMT对象操作
就像 PDO 中的 PDO_Statment 对象一样,MySQLI_STMT 对象也是一个预处理语句所形成的对象,专门用来操作 MySQLi 所生成的预处理语句的.其实操作方式之类也都比较相似,不外 ...
随机推荐
- bluecms安装错误一记
菜鸡兴致勃勃下载了bluecms1.6准备大干一番 环境 phpstudy mysql 5.7.26 apache 2.4.39 php 7.3.4 结果安装第四步发现个这个问题 开始还以为自己这 ...
- NOIP 模拟 7 回家
题解 题目 第一眼,板子题,不就是一个缩点吗?后来一想不对,哪有这么傻的出题人呢,出个这水题. 一想,不对,不仅要求割点,还要判断这个割点是否在搜索树 \(n\) 的祖先上.想到这后,我哈哈大笑,还想 ...
- 题解—P2218 [HAOI2007]覆盖问题
一道不错的题,主要就是一个思路点,想到就行了,想不到就一直卡着. 看完题解之后发现挺简单,实际上自己挣扎半天也咩有想到. 一开始想类比成一维之后贪心,后来被同机房大佬 \(hack\) 掉了. sol ...
- Ubuntu18.04忘记root密码,重置root密码
输入命令,更新root密码: sudo passwd root 然后输入新密码,再输入一次确认新密码,新密码更新完毕! 切换root账号: su 如下图所示,发现已经由zyw账号切换到root账号了!
- 【spring 注解驱动开发】spring事务处理原理
尚学堂spring 注解驱动开发学习笔记之 - 事务处理 事务处理 1.事务处理实现 实现步骤: * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数据源.数据库驱动.Spring-jd ...
- CentOS7 yum方式安装MySQL5.7 + 远程连接
1 下载并安装MySQL官方的 Yum Repository [root@localhost ~]# wget -i -c http://dev.mysql.com/get/mysql57-commu ...
- 【linux】vim常用命令
转自:https://www.runoob.com/linux/linux-vim.html vi/vim 的使用 基本上 vi/vim 共分为三种模式,分别是命令模式(Command mode),输 ...
- Ubuntu中添加desktop entry
创建desktop文件 gedit my_app.desktop 添加文件内容,在启动时,选择加载的bashrc文件,用于初始化,这样可以用不同的desktop entry启动不同的环境,提高打开环境 ...
- pixhawk入门
PX4 是软件名称,代码约30万行 Pixhawk是硬件名称 MissionPlanner是地面站名称 常见术语: WP:Way Point 航电 geofence:地理围栏 Rally Point: ...
- IP掩码的作用
IP地址&IP掩码==网段,即,与上掩码后相同的IP属于同一网段.