咱们持续 MySQLi 扩大的学习,上篇文章中提到过,MySQLi 的扩大绝对于 PDO 来说性能更加的丰盛,所以咱们仍然还会在学习过程中交叉各种 MySQLi 中好玩的办法函数。不过,明天的配角是 MySQLi 中如何执行 SQL 语句以及多条 SQL 语句的执行。
连贯与抉择数据库
首先是一个小内容的学习分享,仍然还是连贯数据库,不过这次咱们用另外一种形式来进行连贯。
<code class="php">$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 对象。
连贯能够切换了,那么咱们要连贯的数据库呢?当然也能够不便地切换。
<code class="php">$mysqli->select_db('mysql');
就是这样一个简略的 select_db() 办法,就能够帮忙咱们在代码执行过程中动静地批改所连贯的数据库。
执行 SQL 语句
对于 PDO 来说,如果是查问语句,咱们须要应用 query() 办法,如果是增、删、改之类的其它语句,咱们要应用 exec() ,通过这两个办法别离执行不同的 SQL 语句。然而在 MySQLi 中,咱们对立只应用 query() 办法就能够了。
<code class="php">$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 是反对的,语句是能够失常执行的,然而咱们拿不到残缺的返回后果。
<code class="php">$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 语句的。
<code class="php">$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() 办法是相同的,也就是说,它是间接执行就将后果集保留在内存中了。
<code class="php">$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://www.php.net/manual/zh/book.mysqli.php
各自媒体平台均可搜寻【硬核项目经理】