1. 今天做了什么
- 完善达人探店功能
- 编写查询笔记(博客)的接口
- 完善点赞业务
- 实现点赞排行榜功能
2. 核心知识点
查询笔记接口
Blog类中的@TableField(exist = false)是 MyBatis-Plus 中的注解,用于标记实体类中的某个字段在数据库表中不存在,从而让 MyBatis-Plus 在生成 SQL 时忽略该字段- 因为
icon和name两个字段仅用于前端展示,数据库没有,故添加该注解
1 |
|
- 查询 blog,查询 user,将用户昵称与头像写入 blog 返回即可
点赞业务
- Redis 用 Set 记录某篇笔记被哪些用户赞过
- 点赞业务逻辑:
- 查 Redis,未赞则更新数据库,更新 Redis;赞过则反之
- 在查询 blog 的业务里,查 Redis,判断是否赞过,将结果写入 blog 返回,这样用户就知道自己有没有赞过了
点赞排行
- 改用 Sorted Set(有序集合),将时间戳作为分数保存,可以确定点赞顺序
- 存:
stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis()); - 删:
stringRedisTemplate.opsForZSet().remove(key, userId.toString()); - 判断是否存在(返回空表示不存在,返回分数则存在):
stringRedisTemplate.opsForZSet().score(key, userId.toString()); - 注意:SQL 语句条件
where in(5,1)传入是无法保证顺序的,需要order by FIELD(id,5,1)
1 | List<UserDTO> userDTOS = userService |
3. 深度思考
这里的点赞肯定存在线程安全问题未处理,如果线程 1 判断未点赞,尚未更新数据库之前,其他线程也判断为点赞,这些线程都会进入数据库,造成一人多赞。可以使用锁,将判断与更新加锁,让同一用户同一笔记的请求串行
这里使用 Redis 存储某笔记被谁赞过,可以判断用户是否赞过某博客,如果有展示用户点赞历史的功能,则不能只存储某笔记被谁赞过,查询遍历全部笔记不现实,应该还要存储某用户赞过哪些笔记
如果并发很高,大量请求修改数据库,会使业务缓慢,数据库压力过大
- 可以使用 day41 学的消息队列,将更新数据库操作加入消息队列,异步执行,但要注意同一用户对同一笔记的消息按顺序消费
- 或者不每次同步数据库,而是 Redis 维护笔记点赞数,定时/定量同步到数据库
- 判断是否点赞,更新点赞数与集合使用 Lua 脚本执行,具有原子性,解决了线程安全问题
- 定时同步,解决了数据库压力的问题