Laravel 7 + MySQL 5.7 无重复点击场景下插入两条相同数据问题求解
重复插入的数据示例:
问题产生原因
排除用户连续点击后,重复插入通常由以下几类原因导致:
- 浏览器预加载机制:现代浏览器默认会对用户可能访问的链接做预请求提前加载资源,用户实际点击前接口已经被调用过一次,点击后触发第二次调用,两次请求间隔极短,对应
created_at字段几乎完全一致。 - 服务端配置的重试规则:Nginx/Apache等反向代理如果配置了不合理的重试规则(比如
proxy_next_upstream包含了非异常场景、超时阈值设置过短),会导致同一个请求被转发两次到Laravel应用。 - 前端逻辑异常:如果点击事件重复绑定、事件冒泡未拦截、未做防抖处理,单次点击也会触发两次提交请求。
- 业务代码逻辑重复:比如插入逻辑被事件监听器、中间件重复调用,或者路由重复绑定了同一处理逻辑。
- 网络波动触发重试:请求响应超时后,浏览器、前端框架、代理层都可能自动发起重试,导致同一个业务请求被执行两次。
解决方案
建议从前端拦截、后端幂等、数据库兜底三个层面联合处理,彻底避免重复插入问题:
前端优化
- 提交类操作统一使用POST/PUT请求,不要使用GET请求,GET请求更容易被预加载、爬虫抓取触发意外调用。
- 点击提交按钮后立即置灰禁用,设置3~5s的冷却时间,避免重复触发。
- 检查点击事件绑定逻辑,避免组件重复渲染时多次绑定同一事件,必要时添加防抖逻辑。
后端逻辑优化
- 新增幂等校验机制:前端每次提交生成唯一的
request_id随请求传入,后端收到后先校验该ID是否已被处理过(可存在Redis或专门的幂等表中,设置1小时过期时间),已处理则直接返回结果,未处理再执行业务逻辑,处理完成后标记该ID为已处理。 - 插入数据优先使用Laravel提供的
firstOrCreate()、updateOrCreate()方法,通过业务唯一条件匹配后再决定是否插入,避免重复执行写入。 - 检查反向代理配置,去掉不必要的重试规则,合理设置超时阈值,避免代理层主动重复转发请求。
数据库兜底
- 针对业务层面的唯一字段组合(例如用户ID+业务标识+操作类型等)建立联合唯一索引,哪怕上层校验全部失效,MySQL也会直接拒绝重复数据的写入,从底层避免脏数据产生。
内容的提问来源于stack exchange,提问作者cchajar
相关产品推荐
相关产品推荐


