feat(note): 实现笔记收藏ZSET更新逻辑
- 移除TODO注释,完善收藏判断逻辑 - 新增Lua脚本实现ZSET收藏列表更新 - 添加ZSET列表不存在时的初始化逻辑 - 实现收藏列表超限移除最早收藏项 - 支持批量同步历史收藏数据到Redis - 设置随机过期时间避免缓存雪崩
This commit is contained in:
@@ -807,7 +807,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
|
|||||||
// 1. 校验被收藏的笔记是否存在
|
// 1. 校验被收藏的笔记是否存在
|
||||||
checkNoteIsExist(noteId);
|
checkNoteIsExist(noteId);
|
||||||
|
|
||||||
// TODO: 2. 判断目标笔记,是否已经收藏过
|
// 2. 判断目标笔记,是否已经收藏过
|
||||||
// 当前登录用户ID
|
// 当前登录用户ID
|
||||||
Long userId = LoginUserContextHolder.getUserId();
|
Long userId = LoginUserContextHolder.getUserId();
|
||||||
|
|
||||||
@@ -875,7 +875,54 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 3. 更新用户 ZSET 收藏列表
|
// 3. 更新用户 ZSET 收藏列表
|
||||||
|
// 3. 更新用户 ZSET 收藏列表
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
// Lua 脚本路径
|
||||||
|
script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/note_collect_check_and_update_zset.lua")));
|
||||||
|
// 返回值类型
|
||||||
|
script.setResultType(Long.class);
|
||||||
|
|
||||||
|
// 执行 Lua 脚本,拿到返回结果
|
||||||
|
result = redisTemplate.execute(script, Collections.singletonList(userNoteCollectZSetKey), noteId, DateUtils.localDateTime2Timestamp(now));
|
||||||
|
|
||||||
|
// 若 ZSet 列表不存在,需要重新初始化
|
||||||
|
if (Objects.equals(result, NoteCollectLuaResultEnum.NOT_EXIST.getCode())) {
|
||||||
|
// 查询当前用户最新收藏的 300 篇笔记
|
||||||
|
Page<NoteCollectionDO> page = noteCollectionDOService.page(new Page<>(1, 300), new LambdaQueryWrapper<>(NoteCollectionDO.class)
|
||||||
|
.select(NoteCollectionDO::getNoteId, NoteCollectionDO::getCreateTime)
|
||||||
|
.eq(NoteCollectionDO::getUserId, userId)
|
||||||
|
.eq(NoteCollectionDO::getStatus, CollectStatusEnum.COLLECT.getCode())
|
||||||
|
.orderByDesc(NoteCollectionDO::getCreateTime));
|
||||||
|
List<NoteCollectionDO> noteCollectionDOS = page.getRecords();
|
||||||
|
// 保底1天+随机秒数
|
||||||
|
long expireSeconds = 60 * 60 * 24 + RandomUtil.randomInt(60 * 60 * 24);
|
||||||
|
|
||||||
|
DefaultRedisScript<Long> script2 = new DefaultRedisScript<>();
|
||||||
|
// Lua 脚本路径
|
||||||
|
script2.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/batch_add_note_collect_zset_and_expire.lua")));
|
||||||
|
// 返回值类型
|
||||||
|
script2.setResultType(Long.class);
|
||||||
|
|
||||||
|
// 若数据库中存在历史收藏笔记,需要批量同步
|
||||||
|
if (CollUtil.isNotEmpty(noteCollectionDOS)) {
|
||||||
|
// 构建 Lua 参数
|
||||||
|
Object[] luaArgs = buildNoteCollectZSetLuaArgs(noteCollectionDOS, expireSeconds);
|
||||||
|
|
||||||
|
redisTemplate.execute(script2, Collections.singletonList(userNoteCollectZSetKey), luaArgs);
|
||||||
|
|
||||||
|
// 再次调用 note_collect_check_and_update_zset.lua 脚本,将当前收藏的笔记添加到 zset 中
|
||||||
|
redisTemplate.execute(script, Collections.singletonList(userNoteCollectZSetKey), noteId, DateUtils.localDateTime2Timestamp(now));
|
||||||
|
} else { // 若无历史收藏的笔记,则直接将当前收藏的笔记 ID 添加到 ZSet 中,随机过期时间
|
||||||
|
List<Object> luaArgs = Lists.newArrayList();
|
||||||
|
luaArgs.add(DateUtils.localDateTime2Timestamp(LocalDateTime.now())); // score:收藏时间戳
|
||||||
|
luaArgs.add(noteId); // 当前收藏的笔记 ID
|
||||||
|
luaArgs.add(expireSeconds); // 随机过期时间
|
||||||
|
|
||||||
|
redisTemplate.execute(script2, Collections.singletonList(userNoteCollectZSetKey), luaArgs.toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: 4. 发送 MQ, 将收藏数据落库
|
// TODO: 4. 发送 MQ, 将收藏数据落库
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
local key = KEYS[1] -- Redis Key
|
||||||
|
local noteId = ARGV[1] -- 笔记ID
|
||||||
|
local timestamp = ARGV[2] -- 时间戳
|
||||||
|
|
||||||
|
-- 使用 EXISTS 命令检查 ZSET 笔记收藏列表是否存在
|
||||||
|
local exists = redis.call('EXISTS', key)
|
||||||
|
if exists == 0 then
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 获取笔记收藏列表大小
|
||||||
|
local size = redis.call('ZCARD', key)
|
||||||
|
|
||||||
|
-- 若已经收藏了 300 篇笔记,则移除最早收藏的那篇
|
||||||
|
if size >= 300 then
|
||||||
|
redis.call('ZPOPMIN', key)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 添加新的笔记收藏关系
|
||||||
|
redis.call('ZADD', key, timestamp, noteId)
|
||||||
|
return 0
|
||||||
Reference in New Issue
Block a user