发布于2026-07-09 阅读(0)
扫一扫,手机访问
说到 Lara vel 点赞功能,最稳妥的数据表结构是多态关联的中间表,而不是把点赞状态塞进 JSON 字段或布尔字段里应付了事。Eloquent 的 belongsToMany 关系天然适配“用户对某篇文章或评论点赞”这种场景,后续加时间戳、取消赞、统计数据等扩展也都方便。
常见错误是什么呢?有人把点赞状态存在 posts.is_liked_by_current_user 这类字段里,每次用户操作都要全表更新,而且查不了“谁点了赞”“点过几次”。这显然不是长久之计。
likes 表至少包含:user_id、likeable_id、likeable_type(实现多态)、created_atHasLikes trait 或直接在 Post、Comment 中定义 likers() 关系increment('likes_count') 做计数器——并发点赞时会丢数据;改用 likes()->count() 或带锁的原子更新
直接用 likes 表 + 多对多中间表结构最稳妥,别图省事用 JSON 字段或布尔字段硬塞。Eloquent 的 belongsToMany 关系天然适配“用户对某篇文章/评论点赞”这种场景,也方便后续加时间戳、取消赞、统计总数等扩展。
常见错误是把点赞状态存在 posts.is_liked_by_current_user 这类字段里——每次用户操作都要全表更新,且无法查“谁点了赞”“点过几次”。
likes 表至少包含:user_id、likeable_id、likeable_type(实现多态)、created_atHasLikes trait 或直接在 Post、Comment 中定义 likers() 关系increment('likes_count') 做计数器——并发点赞时会丢数据;改用 likes()->count() 或带锁的原子更新前端连点两次、刷新后重发、接口被脚本调用……这些都会导致重复插入 likes 记录。靠数据库唯一索引比 PHP 层判断更可靠。
必须给 likes 表加联合唯一约束:UNIQUE(user_id, likeable_id, likeable_type)。Lara vel 迁移里写成:
Schema::create('likes', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->unsignedBigInteger('likeable_id'); $table->string('likeable_type'); $table->timestamps(); $table->unique(['user_id', 'likeable_id', 'likeable_type']);});
插入失败时捕获 Illuminate\Database\QueryException,检查错误码是否为 23000(唯一约束冲突),再返回 409 或静默忽略。
where() 查一遍再插入——竞态条件依然存在firstOrCreate() 替代唯一索引——它仍可能因并发漏判不能每次查列表都 N+1 加载 likers 关系。正确做法是在查询主资源时预加载一个“当前用户是否点赞”的标记字段,用子查询或关联聚合。
推荐用 Lara vel 的 withCount() 配合条件约束:
$posts = Post::withCount(['likers as is_liked' => function ($q) { $q->where('user_id', auth()->id());}])->get();
这样每个 $post 会带一个 is_liked_count 字段(0 或 1),前端直接判断即可。注意字段名是 is_liked_count,不是 is_liked。
$post 调用 $post->likers()->where('user_id', ...)->exists()toArray() 里把 is_liked_count > 0 转成布尔值返回auth()->id(),否则报错当被点赞的模型(比如 Post)启用了软删除,likes 表里仍会存着指向已删除记录的 likeable_id。这会导致 likers() 关系查不到数据,withCount() 统计变少,甚至关联查询报错。
解决方案不是删 likes 记录,而是让关系自动忽略软删除模型:
public function likers(){ return $this->morphToMany(User::class, 'likeable') ->withoutTrashed(); // 关键}
同时确保迁移中 likeable_id 字段允许为 NULL(万一目标模型被强制删除),并在业务逻辑里考虑“点赞对象不存在了”该如何展示(比如显示“内容已不可见”)。
withoutTrashed() 必须显式加,Eloquent 默认不跳过软删除模型likes,只清理无效关联的展示逻辑其实总结下来就三件事:多态关联字段类型、唯一索引覆盖范围、软删除穿透控制。这三个地方一旦漏掉,上线后就容易出现“点不动”“数不对”“查崩溃”的尴尬局面。细节都在迁移和关系定义里,不在控制器里。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8