blog点赞功能的实现

embedded/2025/3/4 20:26:45/

重点1 使用 Set 数据结构实现一人只能点赞一次

选择set的原因

(1)不重复特性:Set 集合中的元素具有唯一性,这与 “一个用户只能对一篇博客点赞一次” 的业务需求高度契合。当用户进行点赞操作时,将用户 ID 作为元素添加到 Set 集合中,如果该用户再次尝试点赞,由于 Set 不允许重复元素,就可以直接判断该用户已经点赞过。

(2)高性能:Set 集合内部基于 Hash 表实现,插入、删除和查找操作的时间复杂度都是 O (1),能够快速处理点赞和取消点赞的操作。

(3)灵活性:一个用户可以对多篇博客进行点赞,使用 Set 集合可以方便地为每篇博客维护一个独立的点赞用户集合,实现一对多的关系。

重点2 使用 SortedSet 数据结构实现点赞排行榜

虽然 Set 数据结构可以实现一人一次点赞的功能,但在实际应用中,很多场景需要对点赞用户进行排序,例如显示最新点赞的用户列表。Set 集合是无序的,无法满足这个需求;而 List 虽然有序,但不具备元素唯一性,且查找效率较低。Sorted Set 则完美地解决了这些问题,它不仅保证元素的唯一性,还可以根据元素的分数进行排序,并且查找效率高。

重点3 实现先点赞的排在前面的需求

问题

在使用 Redis 的 Sorted Set 存储博客点赞信息时,我们通常会将用户点赞的时间戳作为分数存储在 Sorted Set 中。由于 Sorted Set 默认是按照分数从小到大进行排序的,所以后点赞的用户分数更高,会排在前面。但在某些业务场景下,我们希望先点赞的用户排在前面,这就需要对查询结果的排序进行调整。

解决方案思路

为了实现先点赞的用户排在前面,我们需要在从 MySQL 中查询点赞用户信息时,按照 Redis 中 Sorted Set 里用户 ID 的顺序来排列结果。而 MySQL 的 order by field 函数可以帮助我们实现这一需求,它允许我们指定一个字段以及该字段值的排序顺序。

field() 是 MySQL 中的一个函数,它接受一个字段名和一系列的值作为参数。field(id, 5, 1) 表示根据 id 字段的值在 (5, 1) 这个列表中的位置来排序。也就是说,id 为 5 的记录会排在 id 为 1 的记录前面。

相较于Set集合,SortedList有以下不同之处:

对于Set集合我们可以使用 isMember方法判断用户是否存在,对于SortedList我们可以使用ZSCORE方法判断用户是否存在
Set集合没有提供范围查询,无法获排行榜前几名的数据,SortedList可以使用ZRANGE方法实现范围查询

实现流程

(1)查询博客时判断是否点赞

当用户请求查看某篇博客详情或者浏览热门博客列表时。

具体步骤

  • 服务类从 ThreadLocal 中获取当前登录用户的 ID。这是因为在用户登录时,系统会将用户信息存储在 ThreadLocal 中,方便在后续操作中获取用户 ID。
  • 根据博客的 ID 和预定义的 BLOG_LIKED_KEY 构建 Redis 的键名。例如,若 BLOG_LIKED_KEY 为 blog:liked:,博客 ID 为 123,则键名为 blog:liked:123
  • 使用 StringRedisTemplate 的 opsForSet().isMember 方法检查当前用户的 ID 是否存在于该 Redis 的 Set 集合中。如果存在,说明用户已经点赞该博客;如果不存在,则未点赞
  • 将判断结果存储在博客对象的 isLike 属性中,这样在返回博客信息给前端时,前端可以根据该属性决定是否显示已点赞的样式。
  (2)  点赞操作

当用户在博客详情页点击点赞按钮时。

具体步骤

  • 服务类从 ThreadLocal 中获取当前登录用户的 ID,并构建对应的 Redis 键名。
  • 使用 StringRedisTemplate 的 opsForSet().isMember 方法判断用户是否已经点赞该博客。
  • 如果用户未点赞
    • 服务类使用 LambdaUpdateWrapper 构建更新条件,通过 this.update 方法更新 MySQL 数据库中该博客的点赞数,将点赞数加 1。
    • 若数据库更新成功,使用 StringRedisTemplate 的 opsForSet().add 方法将用户 ID 添加到 Redis 的 Set 集合中。这样,下次查询该博客的点赞状态时,就能正确判断用户已经点赞
(3) 取消点赞操作

当用户在已点赞的博客详情页再次点击点赞按钮时。

具体步骤

  • 同样从 ThreadLocal 中获取当前登录用户的 ID,并构建对应的 Redis 键名。
  • 使用 StringRedisTemplate 的 opsForSet().isMember 方法判断用户是否已经点赞该博客。
  • 如果用户已经点赞
    • 服务类使用 LambdaUpdateWrapper 构建更新条件,通过 this.update 方法更新 MySQL 数据库中该博客的点赞数,将点赞数减 1。
    • 若数据库更新成功,使用 StringRedisTemplate 的 opsForSet().remove 方法将用户 ID 从 Redis 的 Set 集合中移除。这样,下次查询该博客的点赞状态时,就能正确判断用户已取消点赞

http://www.ppmy.cn/embedded/170003.html

相关文章

nuxt常用组件库html-validator、@nuxtjs/i18n、@nuxt/image、@unocss/nuxt使用解析

html-validator 主要用于自动验证nuxt服务器呈现的HTML(SSR和SSG),以检测可能导致水合错误的HTML常见问题,有助于减少水合错误,检测常见的可访问性错误。 安装 npx nuxilatest module add html-validator配置 若自动更新nuxt.config.ts配置文…

Oracle 数据库基础入门(四):分组与联表查询的深度探索(上)

在 Oracle 数据库的学习进程中,分组查询与联表查询是进阶阶段的重要知识点,它们如同数据库操作的魔法棒,能够从复杂的数据中挖掘出有价值的信息。对于 Java 全栈开发者而言,掌握这些技能不仅有助于高效地处理数据库数据&#xff0…

网络原理--HTTP协议

http中文名为超文本传输协议,所谓“超文本”就是指传输范围超出了能在UTF8等码表上找到的字符的范围,包含一些图片,特殊格式之类的。 HTTP的发展简介 从图中可以看出到现在已经发展出了HTTP3,但是市面上的主流还是以HTTP1.0为主。…

责任链模式详解和在Spring Boot 项目中的使用场景

责任链模式详解 1. 定义: 责任链模式 (Chain of Responsibility Pattern) 是一种行为型设计模式。它将请求的发送者和接收者解耦,允许你将请求沿着处理者链进行传递,直到有一个处理者处理它为止。每个处理者都包含对下一个处理者的引用&…

小米 SU7 Ultra:科技与性能的极致融合,FPC 隐匿的关键力量【新立电子】

在汽车行业向电动化、智能化转型的浪潮中,小米 SU7 Ultra 以其卓越的性能与前沿科技,强势闯入大众视野,成为众多车迷与科技爱好者瞩目的焦点。这款高性能电动跑车,不仅在动力、操控等方面展现出超凡实力,其内部复杂精妙…

Leetcode 206 -反转链表

Leetcode 206: 反转链表 这是一道非常经典的链表操作题目,要求熟练掌握链表的遍历与指针操作。反转链表是面试中经常出现的题目之一,也是链表题目的基本方法题。 题目描述 输入:一个链表的头节点 head。输出:反转后的链表&#…

使用通义万相Wan2.1进行视频生成

使用通义万相Wan2.1进行视频生成 源代码准备运行环境准备创建Python虚拟环境并激活安装依赖包 模型下载生成视频官网的视频生成例子简单描述场景视频生成示例详细描述场景视频生成示例 最近通义万相开源了其视频生成模型。模型有两个版本,一个是1.3B的,一…

使用Docker Compose部署 MySQL8

MySQL 8 是一个功能强大的关系型数据库管理系统,而 Docker 则是一个流行的容器化平台。结合使用它们可以极大地简化 MySQL 8 的部署过程,并且确保开发环境和生产环境的一致性。 安装 Docker 和 Docker Compose 首先,确保你的机器上已经安装了 Docker 和 Docker Compose。 …