如何阻止用户重复添加同一Widget ID?MySQL校验函数问题修复
问题描述
编写MySQL校验函数check_u_widgets用于避免用户重复添加同一Widget,需求是:不同用户可添加相同Widget,但同一用户不能重复添加同一Widget。但当前函数存在逻辑错误:只要用户添加过任意Widget,就无法再添加其他Widget。
数据表示例
widget_id user_id 1 12 5 12 6 10 9 2 1 2 1 10
当前错误函数代码
public function check_u_widgets($user_id, $widget_id) { global $db, $system; $result = $db->query(sprintf("SELECT * FROM users_widgets WHERE user_id = %s", secure($user_id) )) or _error("SQL_ERROR_THROWEN"); if ($result->num_rows > 0) { $wid = $result->fetch_assoc(); if($wid['widget_id'] == $widget_id) { throw new Exception(__("Sorry, It seem's that this widget is already assigned")); } } return false; }
解决方法
问题根源
原函数仅查询当前用户的第一条Widget记录并对比,存在两个核心问题:
- 无法覆盖用户已添加多个Widget的场景,若要添加的Widget不是查询返回的第一条记录,函数检测不到重复
- 若调用方误将函数返回
false判定为“不可添加”,会导致用户无法添加新的Widget
修正后的校验函数
正确逻辑是直接查询user_id与widget_id的组合是否存在,而非查询用户所有记录:
public function check_u_widgets($user_id, $widget_id) { global $db, $system; // 精准查询当前用户是否已添加该Widget $result = $db->query(sprintf( "SELECT 1 FROM users_widgets WHERE user_id = %s AND widget_id = %s", secure($user_id), secure($widget_id) )) or _error("SQL_ERROR_THROWEN"); if ($result->num_rows > 0) { throw new Exception(__("Sorry, It seems that this widget is already assigned")); } return false; }
优化点说明
- 新增
widget_id查询条件,直接定位目标记录,避免无效数据查询 - 使用
SELECT 1替代SELECT *,仅需判断记录存在性,提升查询性能 - 覆盖所有重复场景,确保同一用户无法重复添加同一Widget
更可靠的数据库层面约束
为彻底避免重复数据,建议给表添加(user_id, widget_id)联合唯一索引,从数据库层面拦截重复插入:
ALTER TABLE users_widgets ADD UNIQUE INDEX idx_user_widget (user_id, widget_id);
简化后的插入函数(可选)
添加唯一索引后,可直接尝试插入数据,捕获数据库重复键错误(错误码1062):
public function add_u_widget($user_id, $widget_id) { global $db, $system; try { $db->query(sprintf( "INSERT INTO users_widgets (user_id, widget_id) VALUES (%s, %s)", secure($user_id), secure($widget_id) )) or _error("SQL_ERROR_THROWEN"); } catch (Exception $e) { // 捕获重复键错误 if ($db->errno === 1062) { throw new Exception(__("Sorry, It seems that this widget is already assigned")); } // 其他错误重新抛出 throw $e; } }
优势
- 数据库约束避免了并发插入时的竞态条件,比应用层校验更可靠
- 简化应用层逻辑,无需额外查询校验
内容的提问来源于stack exchange,提问作者Simon Lewis
相关产品推荐
相关产品推荐

