当前位置: 首页 > 后端技术 > PHP

PHP中PDO操作学习(四)查询结构集

时间:2023-03-29 15:07:14 PHP

上一篇关于PDO的文章,我们就以查询结果集的操作结束吧。在数据库操作中,查询往往占有非常高的比重。在日常开发中,大部分业务都是读多写少,所以掌握查询相关的操作是我们学习的重要内容。和mysqli一样,PDO对查询的支持也非常方便快捷,通过几个函数就可以非常方便高效的操作各种查询语句。在使用preparedstatements的情况下,我们使用execute()执行后,查询的结果集会保存在PDOStatement对象中。数据的操作是传递给PHP对象的,所以我们需要PDOStatement的一些方法来获取结果集的内容。fetch()方法通过fetch()方法获取查询结果集的下一行。$stmt=$pdo->prepare("select*fromzyblog_test_user");$stmt->execute();$row=$stmt->fetch();print_r($row);//数组//(//[id]=>1//[0]=>1//[用户名]=>aaa//[1]=>aaa//[密码]=>aaa//[2]=>aaa//[盐]=>aaa//[3]=>aaa//)从返回结果来看,我们没有为PDO对象指定PDO::ATTR_DEFAULT_FETCH_MODE属性,所以返回的是默认的PDO::FETCH_BOTH格式,即,字段名称和下标同时存在。其实这个方法可以直接指定我们需要的FETCH_STYLE。结果集类型指定$row=$stmt->fetch(PDO::FETCH_ASSOC);print_r($row);//数组//(//[id]=>2//[用户名]=>bbb//[密码]=>bbb//[salt]=>123//)$row=$stmt->fetch(PDO::FETCH_LAZY);print_r($row);//PDORow对象//(//[queryString]=>select*fromzyblog_test_user//[id]=>3//[username]=>ccc//[password]=>bbb//[salt]=>c3//)$row=$stmt->fetch(PDO::FETCH_OBJ);print_r($row);//stdClass对象//(//[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);}//数组//(//[id]=>2//[0]=>2//[用户名]=>bbb//[1]=>bbb//[密码]=>bbb//[2]=>bbb//[盐]=>123//[3]=>123//)//...MySQLdoesnotCursorsupport上面提到的游标操作,PDO扩展支持游标,但是需要注意的是MySQL扩展不支持这个操作。所以我们使用对MySQL库没有影响的游标相关属性。$stmt=$pdo->prepare("select*fromzyblog_test_user",[PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL]);$stmt->执行();$row=$stmt->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_NEXT);print_r($row);//数组//(//[id]=>1//[用户名]=>aaa//[密码]=>aaa//[salt]=>aaa//)$stmt=$pdo->prepare("select*fromzyblog_test_user",[PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL]);$stmt->execute();$row=$stmt->fetch(PDO::FETCH_ASSOC,PDO::FETCH_ORI_LAST);print_r($row);//数组//(//[id]=>1//[用户名]=>aaa//[密码]=>aaa//[salt]=>aaa//)如果是支持游标操作的数据库和扩展,上面代码中fetch()的第二个参数指定后,得到的结果会有所不同。PDO::FETCH_ORI_NEXT是获取游标的下一条数据,PDO::FETCH_ORI_LAST是获取游标的最后一条数据。但是在我们对MySQL的测试中,它们并没有起到任何作用,还是得到了结果集中的下一条数据。fetchAll()方法通过fetch()方法,我们可以得到结果集中所有的数据,但是还是需要循环遍历,有些麻烦。其实PDO已经为我们准备了另外一个方法,fetchAll()返回一个包含结果集中所有行的数组。$stmt=$pdo->prepare("select*fromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll();print_r($list);//数组//(//[0]=>数组//(//[id]=>1//[0]=>1//[用户名]=>aaa//[1]=>aaa//[密码]=>aaa//[2]=>aaa//[盐]=>aaa//[3]=>aaa//)//[1]=>数组//(//[id]=>2//[0]=>2//[用户名]=>bbb//[1]=>bbb//[密码]=>bbb//[2]=>bbb//[盐]=>123//[3]=>123//)//)fetchAll()内部使用fetch()来帮助我们遍历一次结果集并赋值给一个数组。所以如果我们在没有重新执行()的情况下再次调用fetchAll(),我们将得到空数据。因为光标已经到了末尾。$list=$stmt->fetchAll();print_r($list);//Array//(//)也支持指定FETCH_STYLE,和fetch()方法一样,直接把需要的类型常量赋值给第一个参数。//PDO::FETCH_ASSOC$stmt=$pdo->prepare("select*fromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_ASSOC);print_r($list);//Array//(//[0]=>Array//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)//[1]=>数组//(//[id]=>2//[用户名]=>bbb//[密码]=>bbb//[salt]=>123//)//)//PDO::FETCH_COLUMN$stmt=$pdo->prepare("select*fromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_COLUMN,1);print_r($list);//数组//(//[0]=>aaa//[1]=>bbb//)//PDO::FETCH_CLASSclassUser{function__construct($a){echo$a,PHP_EOL;}}$stmt=$pdo->prepare("select*fromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_CLASS,'User',['FetchAllUser']);print_r($list);//FetchAllUser//FetchAllUser//Array//(//[0]=>UserObject//(//[id]=>1//[用户名]=>aaa//[密码]=>aaa//[salt]=>aaa//)//[1]=>用户对象//(//[id]=>2//[username]=>bbb//[password]=>bbb//[salt]=>123//)//)是不是很眼熟,这里就不说了,关于FETCH_STYLE的类型规范已经说了很多遍了,其用法类似于PDO对象中的fetch()和query()方法,但它也支持一种以回调的方式调用方法获取数据集的形式.functiongetValue(){print_r(func_get_args());}//数组//(//[0]=>1//[1]=>aaa//[2]=>aaa//[3]=>aaa//)//数组//(//[0]=>2//[1]=>bbb//[2]=>bbb//[3]=>123//)$stmt=$pdo->prepare("select*fromzyblog_test_userlimit2");$stmt->execute();$list=$stmt->fetchAll(PDO::FETCH_FUNC,'getValue');print_r($list);//数组//(//[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*fromzyblog_test_user");$stmt->execute();$column=$stmt->fetchColumn(2);echo$column,PHP_EOL;//aaa$column=$stmt->fetchColumn(3);echo$column,PHP_EOL;//123fetchObject()方法fetchObject()不用解释了,和fetchColumn(),而是返回下一行数据格式的对象。同样,它也可以传递构造参数,这与PDO对象的query()中指定的PDO::FETCH_CLASS格式的使用相同。我们在第一篇文章中解释过。//fetchObject$stmt=$pdo->prepare("select*fromzyblog_test_user");$stmt->execute();$user=$stmt->fetchObject('User',['FetchObjectUser']);print_r($user);//FetchObjectUser//用户对象//(//[id]=>1//[username]=>aaa//[password]=>aaa//[salt]=>aaa//)rowCount()返回查询结果的个数要得到查询结果集中的行数,需要我们的rowCount()方法。无论是查询还是数据库中的增删改查操作,都会返回语句执行结果,即受影响的行数。此信息是通过rowCount()方法获得的。查询语句返回的行数需要注意的是,在查询语句中,有些数据可能会返回这条语句的行数。但是,不能保证此方法对所有数据都有效,并且不应依赖于便携式应用程序。如果我们需要知道当前查询结果的个数,可以使用fetch()或count(fetchAll())根据实际查询到的结果集的个数来确定本次查询的真实行数。其实就像PDO对象的exec()方法返回的数据一样。在不使用preparedstatements的情况下,直接使用PDO的exec()方法执行SQL语句后,也会返回语句执行后受影响的行数。$stmt=$pdo->prepare("select*fromzyblog_test_user");$stmt->execute();$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//41增、删、改语言返回影响的行数$stmt=$pdo->prepare("insertintozyblog_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("updatezyblog_test_usersetusername=?whereusername=");$stmt->execute(['ccc','cccc']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//25$stmt=$pdo->prepare("updatezyblog_test_usersetusername=?whereusername=?");$stmt->execute(['ccc','cccc']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//0$stmt=$pdo->prepare("从用户名=的zyblog_test_user中删除?");$stmt->execute(['ddd']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//11$stmt=$pdo->prepare("从用户名=的zyblog_test_user中删除?");$stmt->execute(['ddd']);$rowCount=$stmt->rowCount();echo$rowCount,PHP_EOL;//0updateanddelete操作当数据不存在,不更新,不删除时返回0。我们在第一篇PDO相关的文章中也提到了这一点。对于业务而言,这种更新或删除是成功还是失败?或者您应该根据您的实际业务情况来决定!在这里总结一下PDO和PDOStatement相关的内容来学习。我们已经彻底梳理了他们两个的所有方法,也进行了相关的测试。日常使用大家可能接触的不多,框架已经给我们打包好了。不过对于学习来说,可以手写普通的小测试和小调试,加深记忆和理解。在深刻理解了这些扩展类是如何使用之后,反过来,可以帮助我们更清楚地理解框架是如何封装它们的。总之,学习就是从高层到底层,再从底层回到高层,如此循环往复,才能更加得心应手。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E5%9B%9B%EF%BC%89%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%84%E9%9B%86.php参考文档:https://www.php.net/manual/zh/book.pdo.php所有媒体平台均可搜索【硬核项目经理】