
本文介绍如何安全地检查数据库中是否已存在同名记录,并通过唯一约束与预处理语句防止重复插入和sql注入。
本文介绍如何安全地检查数据库中是否已存在同名记录,并通过唯一约束与预处理语句防止重复插入和sql注入。
在开发数据录入功能时,仅执行 INSERT 语句而不校验重复性,极易导致数据冗余甚至业务逻辑错误。以操作(operation)管理为例,若多个相同名称的操作被反复插入,不仅破坏数据一致性,还可能影响后续统计或关联查询。因此,必须从数据库设计与代码实现两个层面协同解决。
✅ 第一步:数据库层 —— 添加唯一约束
首先,在 MySQL 中为 operationname 字段添加唯一索引(或设为主键),这是最根本、最高效的防重机制:
ALTER TABLE operation ADD UNIQUE KEY uk_operationname (operationname);
该约束确保数据库自动拒绝任何违反唯一性的 INSERT 请求,返回明确的错误码(如 1062 Duplicate entry),无需应用层主动查询判断。
✅ 第二步:应用层 —— 使用 INSERT ... ON DUPLICATE KEY UPDATE(可选更新场景)
若业务需求是「存在则更新成本,不存在则新增」,推荐使用 MySQL 的扩展语法:
$operationname = $_POST['operationname'] ?? '';
$cost = (float)($_POST['cost'] ?? 0);
// 使用预处理语句防止 SQL 注入(关键!)
$stmt = $con->prepare("INSERT INTO operation(operationname, cost) VALUES(?, ?) ON DUPLICATE KEY UPDATE cost = ?");
$stmt->bind_param("sds", $operationname, $cost, $cost);
if ($stmt->execute()) {
$data = ['status' => 'success'];
} else {
// 检查是否因唯一冲突导致失败(非其他错误)
if ($con->errno === 1062) {
$data = ['status' => 'duplicated', 'message' => 'Operation name already exists'];
} else {
$data = ['status' => 'failed', 'error' => $con->error];
}
}
echo json_encode($data);
⚠️ 注意:原始代码中直接拼接
$_POST变量构成 SQL 是严重安全隐患,极易引发 SQL 注入攻击。务必改用mysqli::prepare()+bind_param()进行参数化查询。
✅ 替代方案:先 SELECT 再决定 INSERT(不推荐)
虽可行,但存在竞态条件(race condition):两次请求几乎同时执行时,可能均通过 SELECT 检查后各自插入,仍造成重复。因此不建议在高并发场景下采用此方式。
? 总结
-
强制唯一性应由数据库保证:为
operationname添加UNIQUE约束是基石; -
写操作优先使用
ON DUPLICATE KEY UPDATE:简洁、原子、高效; - 永远避免字符串拼接 SQL:统一使用预处理语句绑定参数;
-
错误处理需区分类型:捕获
1062错误码可精准识别重复插入场景,提升用户体验与调试效率。











