Laravel结合Ajax实现点赞系统时likes表重复插入多条记录如何解决
Laravel Ajax点赞重复插入修复方案
核心问题排查
重复插入问题由以下几个错误共同导致:
- 前端JS代码放在了activity循环渲染逻辑中,每渲染一条内容就会给
.likeMain绑定一次点击事件,单次点击会触发多次Ajax请求 - 前端选择器使用全局
$('.id').val()获取ID,多内容场景下永远只会读取第一个点赞按钮的ID - 控制器没有做重复点赞校验,且给Ajax请求返回了重定向响应(重定向仅对普通表单提交有效,对Ajax请求无意义,还可能引发异常重发)
- 没有数据库层面的唯一校验兜底
修复步骤
1. 前端代码修正
将JS代码从activity循环容器中移出,放到页面全局底部(仅加载一次),同时添加请求锁、修正ID选择逻辑:
<!-- 循环渲染的点赞按钮部分保持不变,只移出script代码 --> <div class="container"> @if ( auth()->user()->hasLiked($activity)) <a href="{{ route('reply.unlike', ['id' => $activity->id ]) }}" class="btn btn-danger btn-xs">Unlike</a> @else <a class="btn btn-success btn-xs likeMain"> <input type="hidden" class="id" value="{{ $activity->id }}"> <input type="hidden" class="user-id" value="{{ $activity->user_id }}"> Like </a> @endif </div> <!-- 以下代码放到页面</body>标签之前,全局仅写一次 --> <script> jQuery(document).ready(function ($) { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); // 请求锁,避免请求过程中重复触发 let isLiking = false; // 用事件委托绑定点击事件,适配动态加载的内容 $(document).on('click', '.likeMain', function () { if (isLiking) return; isLiking = true; // 读取当前点击按钮内的隐藏域值,避免全局选择错误 const ActID = $(this).find('.id').val(); const userss = $(this).find('.user-id').val(); $.ajax({ type: 'POST', url: '/replylike', data: { ActID: ActID, userss: userss }, success: function (data) { console.log(data); // 可在此处添加点赞成功后的按钮状态切换逻辑 }, complete: function () { // 请求完成后释放锁 isLiking = false; } }); }); }); </script>
2. 控制器代码修正
添加重复点赞校验,给Ajax请求返回JSON响应,使用firstOrCreate避免重复插入:
public function likeReply(Request $request) { // 匹配到相同用户+相同内容的点赞记录时直接返回,不存在才创建 $like = Like::firstOrCreate( [ 'likeable_id' => $request->ActID, 'likeable_type' => 'App\Activity', 'user_id' => Auth::id() ] ); if (!$like->wasRecentlyCreated) { return response()->json(['status' => 'error', 'msg' => '您已经点赞过该内容']); } return response()->json(['status' => 'success', 'msg' => '点赞成功']); }
3. 数据库层面兜底
给likes表添加唯一联合索引,数据库层面禁止重复点赞记录插入:
执行以下SQL即可:
ALTER TABLE `likes` ADD UNIQUE INDEX `unique_user_like` (`user_id`, `likeable_id`, `likeable_type`);
如果使用Laravel迁移,在likes表的迁移文件中添加以下代码后执行迁移:
$table->unique(['user_id', 'likeable_id', 'likeable_type']);
内容的提问来源于stack exchange,提问作者niel
相关产品推荐
相关产品推荐

