Laravel8表存在重复数据时如何添加唯一索引及避免重复插入问题
解决方案
一、成功添加唯一索引的方法
报错的核心原因是表中已经存在重复的stream_name值,必须先处理完重复数据才能创建唯一索引,操作步骤如下:
- 第一步:查询所有重复的
stream_name记录,确认重复情况
SELECT stream_name, COUNT(*) as count FROM streams GROUP BY stream_name HAVING count > 1;
- 第二步:根据业务需求处理重复数据,两种可选方案:
- 删除重复数据:比如保留ID最小的记录,删除其余重复项,执行SQL:
DELETE s1 FROM streams s1 JOIN streams s2 WHERE s1.id > s2.id AND s1.stream_name = s2.stream_name;- 不删除数据,给重复值加后缀区分:比如给重复的
stream_name拼接_重复{ID}后缀,执行SQL:
UPDATE streams s1 JOIN ( SELECT stream_name, MIN(id) as keep_id FROM streams GROUP BY stream_name HAVING COUNT(*) > 1 ) s2 ON s1.stream_name = s2.stream_name AND s1.id != s2.keep_id SET s1.stream_name = CONCAT(s1.stream_name, '_重复', s1.id); - 第三步:重复数据处理完成后,再执行迁移命令即可成功创建唯一索引。
二、修复addStream方法重复插入的问题
你当前的逻辑存在明显漏洞:验证时使用的是$this->stream_name原始值,插入时使用的是ucwords($this->stream_name)处理后的值,大小写变化会直接绕过验证规则:
比如用户输入non-haz waste,验证时查询数据库是否存在non-haz waste,如果不存在就通过验证,但插入时会转为Non-Haz Waste,如果库中已经存在该值就会出现重复插入。
修复方案如下:
public function addStream($id) { ... // 先把输入值处理成和插入逻辑一致的格式,再做验证 $processedStreamName = ucwords($this->stream_name); $validatedData = Validator::make( ['stream_name' => $processedStreamName], ['stream_name' => 'required|unique:streams'], ['required' => 'Stream Name is Required'], )->validate(); $stream = Stream::create([ 'stream_name' => $processedStreamName ]); ... }
建议必须加上数据库唯一索引作为最后一道防线,避免并发请求同时通过验证导致的重复插入问题。
内容的提问来源于stack exchange,提问作者Charles Smith
相关产品推荐
相关产品推荐

