我们继续 MySQLi 扩展的学习,上篇文章中提到过,MySQLi 的扩展相对于 PDO 来说功能更加的丰富,所以我们依然还会在学习过程中穿插各种 MySQLi 中好玩的方法函数。不过,今天的主角是 MySQLi 中如何执行 SQL 语句以及多条 SQL 语句的执行。

连接与选择数据库

首先是一个小内容的学习分享,依然还是连接数据库,不过这次我们用另外一种方式来进行连接。

$mysqli = new mysqli();
$mysqli->real_connect("localhost", "root", "", "blog_test"); var_dump($mysqli);
// ["thread_id"]=>
// int(163) $mysqli->real_connect("localhost", "root2", "123", "blog_test");
var_dump($mysqli);
// ["thread_id"]=>
// int(164)

首先,我们实例化了一个 mysqli 对象。在实例化过程中,我们并没有给 mysqli 的构造函数传递任何的参数,而是使用 real_connect() 方法来传递数据库服务器信息并建立连接。

相信不少朋友从代码中就可以看出,我们使用 real_connect() 可以在一个 mysqli 实例下来切换不同的数据库连接。通过打印 mysqli 对象的内容就可以看出,两个连接的线程ID不同,也就是说,它们是不同的两个连接,但是使用的都是最上面所初始化的那个 mysqli 对象。

连接可以切换了,那么我们要连接的数据库呢?当然也可以方便地切换。

$mysqli->select_db('mysql');

就是这样一个简单的 select_db() 方法,就可以帮助我们在代码执行过程中动态地修改所连接的数据库。

执行 SQL 语句

对于 PDO 来说,如果是查询语句,我们需要使用 query() 方法,如果是增、删、改之类的其它语句,我们要使用 exec() ,通过这两个方法分别执行不同的 SQL 语句。但是在 MySQLi 中,我们统一只使用 query() 方法就可以了。

$mysqli->query("insert into zyblog_test_user(username, password, salt) values('3a', '3a', '3a')");
var_dump($mysqli->affected_rows);
var_dump($mysqli->insert_id); $mysqli->query("update zyblog_test_user set password='3aa' where username='3a'");
var_dump($mysqli->affected_rows); $mysqli->query("delete from zyblog_test_user where id = 60");
var_dump($mysqli->affected_rows); $res = $mysqli->query("select * from zyblog_test_user where username='3a'");
print_r($res);
// mysqli_result Object
// (
// [current_field] => 0
// [field_count] => 4
// [lengths] =>
// [num_rows] => 3
// [type] => 0
// ) print_r($res->fetch_assoc());
// Array
// (
// [id] => 61
// [username] => 3a
// [password] => 3aa
// [salt] => 3a
// ) while ($row = $res->fetch_assoc()) {
print_r($row);
}
// Array
// (
// [id] => 62
// [username] => 3a
// [password] => 3aa
// [salt] => 3a
// )
// Array
// (
// [id] => 63
// [username] => 3a
// [password] => 3aa
// [salt] => 3a
// )
// ……

对于增、删、改之类的语句,query() 方法只会返回一个布尔值,也就是语句是否执行成功。记住,它返回的不是受影响的行数,这一点是需要注意的。我们如果需要获取受影响的行数需要使用 MySQLi 的属性 affected_rows 。对于插入语句来说,获取最新插入的数据ID使用的是 insert_id 属性。

如果执行的是 SELECT 语句,那么 query() 返回的就是一个 mysqli_result 对象,它代表从一个数据库查询中获取的结果集。关于这个对象的内容我们将在后面的文章中进行详细的说明。

执行多条 SQL 语句

执行多条 SQL 语句的能力对于 PDO 来说是无法实现的,不过据说 PDO 是支持的,语句是可以正常执行的,但是我们拿不到完整的返回结果。

$sql = "insert into zyblog_test_user(username, password, salt) values('3bb', '3bb', '3bb');"
. "update zyblog_test_user set password='3aa' where username='3a';"
. "select * from zyblog_test_user where username='3b';"
. "select now()"; $pdo = new PDO("mysql:dns=locahost;dbname=blog_test", 'root', '', [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$res = $pdo->exec($sql);
var_dump($res); // int(1)
$stmt = $pdo->query($sql);
foreach ($stmt as $row) { //PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error in
var_dump($row);
}

从代码中可以看出,如果使用的是 exec() 方法,那么返回的就是 INSERT 语句的结果。如果使用 query() 方法,返回的虽然是 PDOStatement 对象,但是它是无法遍历的。

接下来我们就看看 MySQLi 是如何来执行这个多条语句拼接在一起的 SQL 语句的。

$mysqli->multi_query($sql);
$i = 1;
do{
echo '第' . $i . '条:', PHP_EOL;
$i++;
$result = $mysqli->use_result();
var_dump($result);
var_dump($mysqli->affected_rows);
if(is_object($result)){
var_dump($result->fetch_assoc());
}
var_dump($mysqli->next_result());
echo '========', PHP_EOL;
} while($mysqli->more_results() );
// 第1条:
// bool(false)
// int(1)
// ========
// 第2条:
// bool(false)
// int(0)
// ========
// 第3条:
// object(mysqli_result)#2 (5) {
// ["current_field"]=>
// int(0)
// ["field_count"]=>
// int(4)
// ["lengths"]=>
// NULL
// ["num_rows"]=>
// int(0)
// ["type"]=>
// int(1)
// }
// int(-1)
// array(4) {
// ["id"]=>
// string(2) "67"
// ["username"]=>
// string(2) "3b"
// ["password"]=>
// string(2) "3b"
// ["salt"]=>
// string(2) "3b"
// }
// ========
// 第4条:
// bool(false)
// int(0)
// ========

multi_query() 就是 MySQLi 提供的执行多条 SQL 语句的方法。通过它执行之后,返回的结果是一个布尔值,如果第一条语句就有问题的话,那么它返回的就是 FALSE 。如果是后面的语句错误了,我们需要调用 next_result() 才能获取后面语句的错误信息。

其实这也引出了我们 next_result() 这个方法的作用。它就相当于是为执行获取下一个结果的操作做准备,也可以看作是将游标移动到了下一条 SQL 语句上。而 more_results() 方法就是判断是否还有更多的语句没有执行。

use_result

在上面的测试代码中,获得每一条语句的执行结果使用的是 use_result() 这个方法。它的作用是启动结果集的检索。也就是说,在 mutli_query() 的时候,这些语句并没有马上执行,而是在调用 use_result() 时,才会执行当前的这条语句。我们注意到 INSERT 、 UPDATE 语句返回的结果都是 FALSE 。而且 SELECT 语句中的 num_rows 也是 0 。这就是它的特点,它也并没有直接将结果集的信息保存在程序的内存中。所以,use_result() 方法最大的好处就是占用内存小,适合大量查询的遍历,缺点则是每次都要去数据库查询,速度慢。

store_result

除了 use_result() 之外,还有一个 store_result() 方法可以帮助我们获得查询的结果集。它和 use_result() 方法是相反的,也就是说,它是直接执行就将结果集保存在内存中了。

$mysqli = new mysqli("localhost", "root", "", "blog_test");

$mysqli->multi_query($sql);
$i = 1;
do{
echo '第' . $i . '条:', PHP_EOL;
$i++;
$result = $mysqli->store_result();
var_dump($result);
var_dump($mysqli->affected_rows);
if(is_object($result)){
var_dump($result->fetch_assoc());
}
var_dump($mysqli->next_result());
echo '========', PHP_EOL;
}
while($mysqli->more_results() );
// 第1条:
// bool(false)
// int(1)
// ========
// 第2条:
// bool(false)
// int(0)
// ========
// 第3条:
// object(mysqli_result)#1 (5) {
// ["current_field"]=>
// int(0)
// ["field_count"]=>
// int(4)
// ["lengths"]=>
// NULL
// ["num_rows"]=>
// int(7)
// ["type"]=>
// int(0)
// }
// int(7)
// array(4) {
// ["id"]=>
// string(2) "67"
// ["username"]=>
// string(2) "3b"
// ["password"]=>
// string(2) "3b"
// ["salt"]=>
// string(2) "3b"
// }
// ========
// 第4条:
// object(mysqli_result)#3 (5) {
// ["current_field"]=>
// int(0)
// ["field_count"]=>
// int(1)
// ["lengths"]=>
// NULL
// ["num_rows"]=>
// int(1)
// ["type"]=>
// int(0)
// }
// int(1)
// array(1) {
// ["now()"]=>
// string(19) "2020-09-14 10:31:37"
// }

不仅查询结果中的 num_rows 有数据了,最后一条 SELECT now(); 语句也成功返回了。它和我们日常使用 query() 的结果是类似的。

另外需要注意的一点是,大家可以看一下我们执行这两条获取结果方式的循环条件是如何写得。more_results() 和 next_result() 针对这两种结果集的获取方式也是不同的,大家可以自己测一下。

总结

光说不练假把式,虽说多语句执行看似很美好,但即使在这简单的测试代码中,也会出现各种问题,大家一定要自己多尝试一下。在日常的开发过程中,最好还是一条一条的语句来执行,避免出现各种无法查明的问题而影响我们正常的业务执行。至于到底要不要使用这个能力,还是大家仁者见仁智者见智了。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/6.PHP中的MySQLi扩展学习(三)mysqli的基本操作.php

参考文档:

https://www.php.net/manual/zh/book.mysqli.php

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

PHP中的MySQLi扩展学习(三)mysqli的基本操作的更多相关文章

  1. PHP中的MySQLi扩展学习(五)MySQLI_STMT对象操作

    就像 PDO 中的 PDO_Statment 对象一样,MySQLI_STMT 对象也是一个预处理语句所形成的对象,专门用来操作 MySQLi 所生成的预处理语句的.其实操作方式之类也都比较相似,不外 ...

  2. PHP中的MySQLi扩展学习(一)MySQLi介绍

    关于 PDO 的学习我们告一段落,从这篇文章开始,我们继续学习另外一个 MySQL 扩展,也就是除了 PDO 之外的最核心的 MySQLi 扩展.可以说它的祖先,也就是 MySQL(原始) 扩展是我们 ...

  3. PHP中的MySQLi扩展学习(六)MySQLI_result对象操作

    在之前的文章中,我们就已经接触过 MYSQLI_result 相关的内容.它的作用其实就是一个查询的结果集.不过在 PDO 中,一般直接通过 query() 或者 PDOStatement 对象进行查 ...

  4. PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句

    对于 MySQLi 来说,事务和预处理语句当然是它之所以能够淘汰 MySQL(原始) 扩展的资本.我们之前也已经学习过了 PDO 中关于事务和预处理语句相关的内容.所以在这里,我们就不再多讲理论方面的 ...

  5. PHP中的MySQLi扩展学习(二)mysqli类的一些少见的属性方法

    虽说是少见的一些属性方法,但是可能还是有不少同学在日常的开发中使用过,这里只是学习了可能相对来说我们用得比较少的一些 mysqli 的属性或方法.就当是扩展一下自己的知识体系. 切换用户 首先就是切换 ...

  6. iOS中 Swift初级入门学习(三)

    // // main.swift // LessonSwift-03 // // Copyright (c) 2015年 韩俊强. All rights reserved. // import Fou ...

  7. phpmyadmin中缺少mysqli扩展 的结解办法

    修改 ;extension=php_mysqli.dll  去掉前面的 ;     以及 调整 php文件夹的目录位置.     这个办法是不是好使,我不确定.这个方法只适合 用win系统 这个,貌似 ...

  8. PHPMyAdmin 显示缺mysqli 扩展的解决方法

    今天在学PHP100视频教程时,装了phpMyAdmin.一开始下载的是最新版本phpMyAdmin-4.1.4-all-languages, 直接500错误,页面怎么也打不开.我用的PHP版本是老版 ...

  9. phpMyAdmin配置及 错误 缺少 mysqli 扩展。请检查 PHP 配置

    PHPMyadmin配置文件config.inc.php内容如下,在需要设置的地方增加了相关注释.     非常适合对数据库操作命令不熟悉的数据库管理者,下面我就说下怎么安装该工具: 1.先到网上下载 ...

随机推荐

  1. Python语言系列-10-数据库

    MySQL 基础环境准备 readme.txt 作者:Alnk(李成果) 版本:v1.0 安装mysql数据库 略 创建student库 # mysql> create database stu ...

  2. Java服务突然失败:A fatal error has been detected by the Java Runtime Environment的总结

    服务启动以后过段时间自动失败:A fatal error has been detected by the Java Runtime Environment 控制台中的错误信息 A fatal err ...

  3. ECC(Ellipse Curve Cryptography)+AES(Advanced Encryption Standard)前端通讯加密模拟(使用eccrypto-js)

    前置知识 不了解对称加密与非对称加密的小伙伴可以看看下面的文章,想详细学习与区块链有关的加密算法可以戳这里 对称与非对称加密 https://blog.csdn.net/u013320868/arti ...

  4. IOC概念和原理:BeanFactory 接口与ApplicationContext

    IOC(概念和原理)1.什么是 IOC(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理(2)使用 IOC 目的:为了耦合度降低(3)做入门案例就是 IOC 实现2.IOC ...

  5. C#多线程---Task实现异步

    一.场景 使用Task来进行累加操作. 二.例子-Task使用 1 using System; 2 using System.Collections.Generic; 3 using System.L ...

  6. SpringCloud升级之路2020.0.x版-24.测试Spring Cloud LoadBalancer

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 通过单元测试,我们 ...

  7. Python也可以拥有延迟函数

    延迟函数defer 我们知道在Golang中有一个关键字defer,用它来声明在函数调用前,会让函数*延迟**到外部函数退出时再执行,注意,这里的退出含义:函数return返回或者函数panic退出 ...

  8. netty系列之:自建客户端和HTTP服务器交互

    目录 简介 使用客户端构建请求 accept-encoding server解析HTTP请求 总结 简介 上一篇文章,我们搭建了一个支持中文的HTTP服务器,并且能够从浏览器访问,并获取到相应的结果. ...

  9. linux shell 脚本输入参数解析

    文件名: test.sh #!/bin/bash para="para: "; while [ $# -ge 2 ] ; do case "$1" in --a ...

  10. Java基础之SPI机制

    SPI 机制,全称为 Service Provider Interface,是一种服务发现机制.它通过在 ClassPath 路径下的 META-INF/services 文件夹查找文件,自动加载文件 ...