PHP MySQL Delete
在PHP中,从MySQL数据库删除数据是一个常见操作,但也是一个需要格外小心的操作。本教程将详细介绍如何使用PHP和MySQL DELETE语句安全地从数据库中删除数据,包括基本的删除操作、条件删除以及如何防止意外删除整个表的数据。
基本的DELETE语句
DELETE语句用于从数据库表中删除记录。与UPDATE语句一样,DELETE语句也应该总是包含WHERE子句来指定要删除的记录,否则将删除表中的所有记录。
1. MySQLi面向对象方式
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// SQL删除语句
$sql = "DELETE FROM MyGuests WHERE id=3";
if ($conn->query($sql) === TRUE) {
echo "记录删除成功";
} else {
echo "删除错误: " . $conn->error;
}
// 关闭连接
$conn->close();
?>
2. MySQLi过程式方式
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 创建连接
$conn = mysqli_connect($servername, $username, $password, $dbname);
// 检查连接
if (!$conn) {
die("连接失败: " . mysqli_connect_error());
}
// SQL删除语句
$sql = "DELETE FROM MyGuests WHERE id=3";
if (mysqli_query($conn, $sql)) {
echo "记录删除成功";
} else {
echo "删除错误: " . mysqli_error($conn);
}
// 关闭连接
mysqli_close($conn);
?>
3. 使用PDO
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 尝试连接数据库
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8mb4", $username, $password);
// 设置PDO错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL删除语句
$sql = "DELETE FROM MyGuests WHERE id=3";
// 执行查询
$conn->exec($sql);
echo "记录删除成功";
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
// 关闭连接
$conn = null;
?>
警告:在没有WHERE子句的情况下执行DELETE语句将删除表中的所有记录!这是一个不可逆的操作,请务必谨慎操作。
使用WHERE子句删除特定记录
WHERE子句在DELETE语句中至关重要,它指定了哪些记录应该被删除。以下是一些使用不同条件的WHERE子句示例。
<?php
// 数据库连接代码...
// 使用不同条件的WHERE子句
// 1. 根据ID删除
$sql1 = "DELETE FROM MyGuests WHERE id=10";
// 2. 使用比较运算符
$sql2 = "DELETE FROM products WHERE stock = 0"; // 删除库存为0的产品
// 3. 使用LIKE进行模糊匹配
$sql3 = "DELETE FROM users WHERE email LIKE '%@spamdomain.com'"; // 删除特定域名的用户
// 4. 使用IN子句
$sql4 = "DELETE FROM orders WHERE order_id IN (2001, 2002, 2003)";
// 5. 使用AND/OR组合条件
$sql5 = "DELETE FROM logs WHERE type='error' AND timestamp < '2023-01-01'"; // 删除2023年之前的错误日志
// 6. 使用日期条件
$sql6 = "DELETE FROM sessions WHERE last_activity < NOW() - INTERVAL 30 DAY"; // 删除30天未活动的会话
// 执行其中一个删除操作
if ($conn->query($sql1) === TRUE) {
echo "记录删除成功";
} else {
echo "删除错误: " . $conn->error;
}
?>
使用预处理语句防止SQL注入
当删除操作涉及用户输入时,必须使用预处理语句来防止SQL注入攻击。预处理语句将SQL逻辑与数据分开处理,确保用户输入不会被误解为SQL代码。
1. MySQLi预处理语句
<?php
// 数据库连接代码...
// 假设这是来自用户的输入数据
$id = $_POST['id'];
// 创建预处理语句
$stmt = $conn->prepare("DELETE FROM MyGuests WHERE id=?");
$stmt->bind_param("i", $id);
// 执行预处理语句
if ($stmt->execute()) {
echo "记录删除成功";
} else {
echo "删除错误: " . $stmt->error;
}
// 关闭语句
$stmt->close();
?>
2. PDO预处理语句
<?php
// 数据库连接代码...
// 假设这是来自用户的输入数据
$id = $_POST['id'];
try {
// 准备预处理语句
$stmt = $conn->prepare("DELETE FROM MyGuests WHERE id=:id");
// 绑定参数
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
// 执行预处理语句
$stmt->execute();
echo "记录删除成功";
} catch(PDOException $e) {
echo "删除错误: " . $e->getMessage();
}
?>
获取受影响的行数
了解DELETE语句删除了多少行可以帮助您确认操作是否成功,并提供有用的反馈信息。
1. MySQLi获取受影响行数
<?php
// 数据库连接代码...
// 执行删除语句
$sql = "DELETE FROM MyGuests WHERE last_login < '2022-01-01'";
if ($conn->query($sql) === TRUE) {
$affected_rows = $conn->affected_rows;
echo "记录删除成功,受影响的行数: " . $affected_rows;
} else {
echo "删除错误: " . $conn->error;
}
// 使用预处理语句时获取受影响行数
$stmt = $conn->prepare("DELETE FROM MyGuests WHERE id=?");
$stmt->bind_param("i", $id);
$stmt->execute();
$affected_rows = $stmt->affected_rows;
echo "预处理语句删除,受影响的行数: " . $affected_rows;
?>
2. PDO获取受影响行数
<?php
// 数据库连接代码...
try {
// 使用exec()方法获取受影响行数
$sql = "DELETE FROM MyGuests WHERE last_login < '2022-01-01'";
$affected_rows = $conn->exec($sql);
echo "记录删除成功,受影响的行数: " . $affected_rows;
// 使用预处理语句时获取受影响行数
$stmt = $conn->prepare("DELETE FROM MyGuests WHERE id=:id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$affected_rows = $stmt->rowCount();
echo "预处理语句删除,受影响的行数: " . $affected_rows;
} catch(PDOException $e) {
echo "删除错误: " . $e->getMessage();
}
?>
使用事务进行相关删除操作
当您需要执行多个相关的删除操作时,使用事务可以确保数据的一致性。事务允许您将一组操作视为单个原子操作:要么全部成功,要么全部失败。
1. MySQLi事务
<?php
// 数据库连接代码...
// 开始事务
$conn->begin_transaction();
try {
// 删除用户及其所有相关数据
// 1. 删除用户的评论
$sql1 = "DELETE FROM comments WHERE user_id=10";
$conn->query($sql1);
// 2. 删除用户的订单
$sql2 = "DELETE FROM orders WHERE user_id=10";
$conn->query($sql2);
// 3. 最后删除用户记录
$sql3 = "DELETE FROM users WHERE id=10";
$conn->query($sql3);
// 提交事务
$conn->commit();
echo "用户及其相关数据已成功删除";
} catch (Exception $e) {
// 发生错误时回滚事务
$conn->rollback();
echo "事务回滚: " . $e->getMessage();
}
?>
2. PDO事务
<?php
// 数据库连接代码...
try {
// 开始事务
$conn->beginTransaction();
// 删除用户及其所有相关数据
// 1. 删除用户的评论
$sql1 = "DELETE FROM comments WHERE user_id=10";
$conn->exec($sql1);
// 2. 删除用户的订单
$sql2 = "DELETE FROM orders WHERE user_id=10";
$conn->exec($sql2);
// 3. 最后删除用户记录
$sql3 = "DELETE FROM users WHERE id=10";
$conn->exec($sql3);
// 提交事务
$conn->commit();
echo "用户及其相关数据已成功删除";
} catch (PDOException $e) {
// 发生错误时回滚事务
$conn->rollBack();
echo "事务回滚: " . $e->getMessage();
}
?>
安全删除数据的替代方案
在某些情况下,您可能不想真正删除数据,而是希望保留它但将其标记为已删除。这种方法称为"软删除",在许多应用程序中很常见。
软删除示例
<?php
// 数据库连接代码...
// 软删除:不是真正删除记录,而是更新标记字段
$sql = "UPDATE users SET deleted=1, deleted_at=NOW() WHERE id=5";
if ($conn->query($sql) === TRUE) {
echo "用户已标记为删除";
} else {
echo "标记删除错误: " . $conn->error;
}
// 查询时排除已删除的记录
$sql = "SELECT id, username, email FROM users WHERE deleted=0";
$result = $conn->query($sql);
?>
删除数据的最佳实践
- 始终使用WHERE子句:除非您确实需要删除表中的所有记录,否则一定要包含WHERE子句
- 使用预处理语句:当删除操作涉及用户输入时,使用预处理语句防止SQL注入
- 验证和过滤用户输入:在执行删除操作之前,验证和过滤所有用户输入的数据
- 使用事务处理相关删除:当需要删除多个相关表中的数据时,使用事务确保数据一致性
- 考虑使用软删除:对于重要数据,考虑使用软删除替代物理删除
- 实施权限控制:限制哪些用户可以执行删除操作
- 数据备份:在执行批量删除前,确保有最新的数据备份
- 测试删除操作:在生产环境中执行删除操作前,先在测试环境中验证
- 记录删除操作:对于重要数据,记录删除操作的日志,包括谁做的删除,删除的内容等
- 使用级联删除:在数据库设计时,考虑使用外键和级联删除来自动维护引用完整性
- 限制单次删除的记录数量:对于大型表,考虑分批删除数据,而不是一次删除大量记录
常见陷阱和错误
- 忘记WHERE子句:这是最危险的错误之一,可能导致整个表的数据被意外删除
- 不安全的用户输入处理:直接在SQL语句中使用未验证的用户输入,可能导致SQL注入攻击
- 忽略外键约束:尝试删除有外键约束的记录而不先删除引用它的记录,会导致错误
- 不处理事务回滚:在执行多个相关删除时,不使用事务或不处理错误回滚,可能导致数据不一致
- 过度删除:删除比需要更多的数据,没有考虑数据的潜在价值或法律要求
- 不考虑性能影响:在高峰期执行大量删除操作,可能影响数据库性能
- 忽略索引:在WHERE子句中不使用索引列,可能导致删除操作速度很慢