在本教程中,我们将学习如何使用 PHP 中的 MYSQLI 准备语句执行不同条件的查询,如 SELECT、UPDATE、DELETE 等。在我们开始之前,我将简要介绍您准备好的陈述。
什么是 MYSQLI 准备好的语句?
MYSQL是一种流行的关系数据库系统。MYSQLI是一个强大的 PHP 扩展,用于连接 MYSQL。准备好的语句作为先前准备并稍后使用数据执行的查询。
为什么准备好的陈述很重要?
简单地说,准备好的语句保护网站免受可用于攻击网站的SQL 注入。此外,根据某些来源,准备好的语句可能比普通查询更快(但是,根据我的经验,它们在执行简单查询时几乎相同。但是,对于重复查询,准备好的语句比普通查询快)。准备好的语句最好的地方是可读性。它们很容易被阅读、理解和管理。
先决条件
在开始之前,您将需要这些东西。
- 安装了 PHP 和 MYSQL 的计算机。
- 已连接到数据库的 PHP 脚本。我们将把数据库连接保存在$mysqli中。
<?php $mysqli = new mysqli( 'hostname', 'username', 'password', 'database' );
- 在本教程中,我们的数据库中将有一个这样的“user”表
id name email 1 Teodor teod@gmail.com 2 Christ christoperkhawand@gmail.com 3 Austin austin@gmail.com 4 Ayush ayushagarwal@gmail.com
如何在 PHP 中使用准备好的语句
让我们看看如何使用 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'。
无缘无故,在 PHP 中,以下内容无效。bind_param函数的参数应该是除第一个之外的变量。$stmt -> bind_param('i', 2);
- 接下来,我们执行查询
在此步骤之后,过程会根据您将执行的查询而有所不同。让我们看一些例子。$stmt -> execute();
1. SELECT - 选择一行
$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
- store_result()存储结果。
- bind_result()将值绑定到变量。
- fetch()将结果提取到变量中。
起初,如果您是初学者,这很棘手。但是,当您执行其他步骤时,您会明白。请记住,fetch()将当前行的结果保存在bind_result()的变量中。默认情况下,当前行是结果集中的第一行。当我们调用一次fetch()时,当前行是结果中的第二行。但是,我们在此查询中只有一行。
2. SELECT - 选择多行
$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()函数。这将选择所有用户并回显所有用户的姓名和电子邮件。
特别说明:
- fetch()成功时返回 true,失败时返回 false。如果没有找到行,它将返回 false。所以,我们可以直接用它作为while循环的条件。
- 在每次调用fetch()时,当前行的结果都保存在$name和$email变量中。并且,光标移动到下一行。(所以,当我们下次调用 fetch 时,它会获取下一行)
3. SELECT - 获取所选行数
$stmt = $mysqli -> prepare('SELECT name, email FROM users');
$stmt -> execute();
$stmt -> store_result();
// 4
echo $stmt -> num_rows;
需要记住的一件事是,应该在使用num_rows属性之前调用store_result() 。
4. 选择 - 获取结果
$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'];
}
5. SELECT - 带通配符
通配符用于匹配 MYSQL 中的模式。
<?php
$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 准备好的语句的最佳方法,那么本文适合您。我正在等待在评论部分看到您的反馈。感谢您的阅读!