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() 方法就是判断是否还有