点赞功能
点赞这个功能它的内容是什么?
- 用户点赞/取消点赞(如果没有点赞,则点赞成功,如果已经点赞了则取消点赞)
- 获取内容列表时,要知道每个内容用户的点赞状态
- 获取到用户点赞的内容
- 显示某个内容点赞的N个用户(通常在内容列表里不这么干,掘金是这么干的。微博在内容列表只有点赞数量,某些网站在内容详情才会显示前N个点赞的用户)
微博的只有数量
实现
在不考虑性能,数据安全性的问题上,我们先从一个人的动作开始思考如何实现点赞。
使用mysql+redis实现
可以创建一张表,用于保存点赞数据
- ID
- 内容ID
- 用户ID
- 创建时间
- 更新时间
简单的字段,就可以记录点赞数据了。
点赞和取消点赞:
- 根据用户ID和内容ID从数据库中删除,如果删除成功就返回取消点赞成功
- 如果删除失败就添加入库,返回点赞成功。
- 此时要根据内容ID修改内容的点赞数量
获取列表时,要知道每个内容当前用户的点赞状态
- 内容里加多一个字段hasThumb,用于表示是否点赞。
- 如果当前请求用户没有登录,全部是false默认值
- 如果当前用户已经登录了,就要判断是否有点赞了。
怎么判断呢?
方法也是多种的
- 列表出来以后,再去根据id去查询是否已经点赞了,这样子的话效率也不高。
- 通过用户ID插叙出当前用户的所有点赞内容,然后转在k-v的方式,遍历一次动态列表就知道是否有点赞了。这种方法在用户点赞过的内容比较少的情况下可用。
- 如果点赞多了怎么办呢?我们的列表是根据时间排序的,可以知道最后一条的时间最晚。所以获取用户的点赞列表时,限制一下当前时间到最晚发表的动态时间即可查出当前内容有可能点赞的列表来。比当前内容更晚的时间不可能点赞的吧。
如果内容和点赞状态帮定到一起,那么每个人访问的都是不一样的数据,缓存起来会有大量的缓存,占用太多资源。 为了提高效率,我们可以内容和点赞分开缓存。也就是说,内容独立缓存在redis里,里面的hasThumb全部是false,如果用户没登录,返回内容缓存。
如果用户登录了,才去查询内容的点赞状态。甚至点赞状态也可以缓存起来,以此提高响应的速度。
获取到用户的点赞内容
这个还是比较简单的,根据用户id获取到点赞列表联立内容列表进行查询即可获取到用户点赞过的内容列表。
显示某个内容点赞的N个用户
如果只有某个内容的页面需要,效率也不算太影响。
根据内容的ID,去查询出点赞的用户即可,限制个数,时间排序。
如果列表中要显示,像掘金那样子,每一个内容都去查询一下消耗的资源就比较多了。
使用redis实现
redis实现我们通过set或者zset集合来存储即可,不需要去设计数据结构。但也是有结构的
key-set结构。我们可以用前缀_内容ID为key,该内容的点赞用户ID列表为内容。
比如说1号文章有1,2,3号用户点赞,那么key就是:content:1,set里有1,2,3号用户的ID.
点赞和取消点赞
- 根据当前的内容ID判断当前的用户ID是否在对应内容的集合里
- 如果存在,就修内容的点赞数量-1,并且从redis中删除内容点赞集合里的该用户ID
- 如果不存在,修改内容点赞数量+1,把当前用户的ID添加到内容的点赞集合中
获取列表时,要知道每个内容当前用户的点赞状态
- 查询到内容列表
- 如果用户未登录,全部内容点赞为false
- 如果用户已经登录,根据内容的ID和用户ID从redis里判断是否有点赞
获取到用户的点赞内容
不好查询,如果我们把用户的点赞内容放到一个list获取set里。如果用户点赞内容过多则容易出现bigkey。最好还是结合mysql,存储到mysql中。获取某个用户的点赞内容这个接口调用的频率不算高。
显示某个内容点赞的N个用户
如果只是内容更页面获取,我们可以用zset,把时间戳作为分数值,查询的时候通过范围去获取一下即可,比如说获取前5个人,0~4即可。查出来了,还要去查用户的头像。把列表作为参数给到mysql查询,in的查询也比较耗资源的。
如果是列表查询也是跟上面方法差不多,只是要遍历。这个操作呀,真的不建议放在内容列表上。
摸鱼君适合哪一种呢?
第一种,mysql查询比较多,速度上没有redis快。但是成本比较低。 第二种,redis速度快,数据在内存上,要考虑安全性。通常要部署高可用的redis,同时还要进行数据持久化,开启AOF。如果开启AOF,随着时间变长,持久化的数据会变大,要监控好,准备扩容。这个成本比较高。
摸鱼君适合哪一种呢?看功能,看规模。
像摸鱼君这种点赞数量并不多的网站,mysql+redis缓存就可以了。
对于某个用户来说,点赞,前端直接+1即可,不需要马上去获取到最新的数据。否则可能会出现一个点赞数量大增的情况,如果同时多人点赞的话。
所以内容缓存起来,点赞数量不一定准确,只要确保点赞状态准确就可以了。
相关文章: