在本教程中,我们将学习如何使用 PHP 中的 MYSQLI 准备语句执行不同条件的查询,如 SELECT、UPDATE、DELETE 等。在我们开始之前,我将简要介绍您准备好的陈述。
MYSQL是一种流行的关系数据库系统。MYSQLI是一个强大的 PHP 扩展,用于连接 MYSQL。准备好的语句作为先前准备并稍后使用数据执行的查询。
简单地说,准备好的语句保护网站免受可用于攻击网站的SQL 注入。此外,根据某些来源,准备好的语句可能比普通查询更快(但是,根据我的经验,它们在执行简单查询时几乎相同。但是,对于重复查询,准备好的语句比普通查询快)。准备好的语句最好的地方是可读性。它们很容易被阅读、理解和管理。
在开始之前,您将需要这些东西。
- $mysqli = new mysqli( 'hostname', 'username', 'password', 'database' );
| id | name | |
|---|---|---|
| 1 | Teodor | teod@gmail.com |
| 2 | Christ | christoperkhawand@gmail.com |
| 3 | Austin | austin@gmail.com |
| 4 | Ayush | ayushagarwal@gmail.com |
让我们看看如何使用 MYSQLI 在 PHP 中执行准备好的语句。这是基本概念。在各种查询(SELECT、UPDATE 等)中,我们将使用不同的方式(和技巧)。
$stmt = $mysqli -> prepare('SELECT * FROM users WHERE id = ?'); 在这里,我们将语句存储在$stmt中。这是一个mysqli_stmt对象。在接下来的步骤中,我们将调用此类的方法来执行操作。
请注意? 查询中的(问号)用作占位符。我们对 MYSQL 说这是一个空盒子,我们将在未来填充它。
- $userId = 2;
- $stmt -> bind_param('i', $userId);
这里我们将绑定2作为用户的 id。在bind_param()方法中,第一个参数表示每个变量的数据类型。例如,如果您要绑定三个变量(空框),它们分别是整数、整数、字符串、整数,您可以使用'iisi'。
$stmt -> bind_param('i', 2);
$stmt -> execute(); 在此步骤之后,过程会根据您将执行的查询而有所不同。让我们看一些例子。- $stmt = $mysqli -> prepare('SELECT name, email FROM users WHERE id = ?');
-
- $userId = 1; // or $_GET['userId'];
-
- $stmt -> bind_param('i', $userId);
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
- $stmt -> fetch();
-
- echo $name; // Teodor
- echo $email; // teod@gmail.com
起初,如果您是初学者,这很棘手。但是,当您执行其他步骤时,您会明白。请记住,fetch()将当前行的结果保存在bind_result()的变量中。默认情况下,当前行是结果集中的第一行。当我们调用一次fetch()时,当前行是结果中的第二行。但是,我们在此查询中只有一行。
- $stmt = $mysqli -> prepare('SELECT name, email FROM users');
-
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
-
- while ($stmt -> fetch()) {
- echo $name;
- echo $email;
- }
当您没有任何要传递的变量时,不需要bind_param()函数。这将选择所有用户并回显所有用户的姓名和电子邮件。
特别说明:
- $stmt = $mysqli -> prepare('SELECT name, email FROM users');
-
- $stmt -> execute();
- $stmt -> store_result();
- // 4
- echo $stmt -> num_rows;
需要记住的一件事是,应该在使用num_rows属性之前调用store_result() 。
- $stmt = $mysqli -> prepare('SELECT name, email FROM users WHERE id > ?');
-
- $greaterThan = 1;
- $stmt -> bind_param('i', $greaterThan);
- $stmt -> execute();
- $result = $stmt -> get_result();
现在$result与$mysqli -> query(...)相同。您可以使用以下内容来使用结果。
- while ($row = $result -> fetch_assoc()) {
- echo $row['name'];
- echo $row['email'];
- }
通配符用于匹配 MYSQL 中的模式。
- $stmt = $mysqli -> prepare('SELECT name, email FROM users WHERE name LIKE ?');
-
- $like = 'a%';
- $stmt -> bind_param('s', $like);
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
-
- while ($stmt -> fetch()) {
- echo $name;
- echo $email;
- }
在此示例中,我们将选择名称以字母a开头的所有用户。(奥斯汀和阿尤什)
6. SELECT - 带有 ID 数组
在使用准备好的语句时,这是一件非常困难的事情。我们需要动态地将问号添加到查询中。
- // array of user IDs
- $userIdArray = [1,2,3,4];
- // number of question marks
- $questionMarksCount = count($userIdArray);
- // create a array with question marks
- $questionMarks = array_fill(0, $questionMarksCount, '?');
- // join them with ,
- $questionMarks = implode(',', $questionMarks);
- // data types for bind param
- $dataTypes = str_repeat('i', $questionMarksCount);
-
- $stmt = $mysqli -> prepare("SELECT name, email FROM users WHERE id IN ($questionMarks)");
-
- $stmt -> bind_param($dataTypes, ...$userIdArray);
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
-
- while ($stmt -> fetch()) {
- echo $name;
- echo $email;
- }
7. 选择 - 限制和偏移
- $stmt = $mysqli -> prepare("SELECT name, email FROM users LIMIT ? OFFSET ?");
-
- // limit of rows
- $limit = 2;
- // skip n rows
- $offset = 1;
-
- $stmt -> bind_param('ii', $limit, $offset);
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
-
- while ($stmt -> fetch()) {
- echo $name;
- echo $email;
- }
8. 选择 - 之间
- $stmt = $mysqli -> prepare("SELECT name, email FROM users WHERE id BETWEEN ? AND ?");
-
- $betweenStart = 2;
- $betweenEnd = 4;
-
- $stmt -> bind_param('ii', $betweenStart, $betweenEnd);
- $stmt -> execute();
- $stmt -> store_result();
- $stmt -> bind_result($name, $email);
-
- while ($stmt -> fetch()) {
- echo $name;
- echo $email;
- }
9. 插入 - 一行
- $stmt = $mysqli -> prepare('INSERT INTO users (name, email) VALUES (?,?)');
-
- $name = 'Akhil';
- $email = 'akhilkumar@gmail.com';
-
- $stmt -> bind_param('ss', $name, $email);
- $stmt -> execute();
10. INSERT - 获取插入 ID
如果您有一个用于保存 ID 的自动增量列,在许多情况下,我们需要知道我们刚刚插入数据库的用户的 ID 是什么。在这种情况下使用$stmt -> insert_id属性。
- $stmt = $mysqli -> prepare('INSERT INTO users (name, email) VALUES (?,?)');
-
- $name = 'Akhil';
- $email = 'akhilkumar@gmail.com';
-
- $stmt -> bind_param('ss', $name, $email);
- $stmt -> execute();
-
- echo 'Your account id is ' . $stmt -> insert_id;
11. INSERT - 多行(递归)
使用准备好的语句完成递归插入非常强大。我们准备一个语句并使用它来插入多行。
- $newUsers = [
- [ 'sulliops', 'sulliops@gmail.com' ],
- [ 'infinity', 'infinity@gmail.com' ],
- [ 'aivarasco', 'aivarasco@gmail.com' ]
- ];
-
- $stmt = $mysqli -> prepare('INSERT INTO users (name, email) VALUES (?,?)');
-
- foreach ($newUsers as $user) {
-
- $name = $user[0];
- $email = $user[1];
-
- $stmt -> bind_param('ss', $name, $email);
- $stmt -> execute();
-
- echo "{$name}'s account id is {$stmt -> insert_id}";
-
- }
每次插入新行时,您都会看到$stmt -> insert_id更新。
12. 更新
- $stmt = $mysqli -> prepare('UPDATE users SET email = ? WHERE id = ? LIMIT 1');
-
- $email = 'newemail@hyvor.com';
- $id = 2;
-
- $stmt -> bind_param('si', $email, $id);
- $stmt -> execute();
13. 更新 - 获取受影响的行
有时您需要知道我们的 UPDATE 查询影响了多少行。
- $stmt = $mysqli -> prepare('UPDATE users SET email = ? WHERE name = ? LIMIT 1');
-
- $email = 'newemail@hyvor.com';
- $name = 'teodor';
-
- $stmt -> bind_param('ss', $email, $name);
- $stmt -> execute();
-
- // 1
- echo $stmt -> affected_rows;
14. 删除
- $stmt = $mysqli -> prepare('DELETE FROM users WHERE id = ?');
-
- $userId = 4;
-
- $stmt -> bind_param('i', $userId);
- $stmt -> execute();
-
- // number of deleted rows
- echo $stmt -> affected_rows;
处理错误
知道如何调试 MYSQLI 准备好的语句总是很好的。这里有一些提示。
1. 准备失败时
有时$mysqli -> prepare()函数会因为查询错误而失败。
如何检测?
- $stmt = $mysqli -> prepare('SELECT * FROM no_table WHERE id = ?');
-
- $id = 1;
- $stmt -> bind_param('i', $id);
如果您在调用$stmt的方法时 看到 PHP 中的错误,例如“在布尔值上调用成员函数 bind_param()”,则说明准备工作失败。当$mysql -> prepare()失败时,它返回false。因此$stmt是一个布尔值,而不是一个对象。现在我们可以使用$mysqli -> error来查找查询中的错误。
- $stmt = $mysqli -> prepare('SELECT * FROM no_table WHERE id = ?');
- echo $mysqli -> error;
2. 执行失败时
执行失败通常不会引发错误。因此,您应该添加一个条件来检查执行是否成功。如果不是,$stmt -> error会告诉你什么是错误。
- $stmt = $mysqli -> prepare('INSERT INTO stmt_users (name) VALUES (?)');
-
- $name = 'User';
- $stmt -> bind_param('i', $name);
-
- if (! $stmt -> execute()) {
- echo $stmt -> error;
- }
对于我们的示例表,错误是"Field 'email' doesn't have a default value"。
结论
我的目标是涵盖在本教程中执行准备好的语句的所有方法。我们讨论了如何为 SELECT、INSERT、UPDATE 和 DELETE 使用准备好的语句。所以,我希望我涵盖了所有内容。如果您愿意学习执行 MYSQLI 准备好的语句的最佳方法,那么本文适合您。我正在等待在评论部分看到您的反馈。感谢您的阅读!