feat(comment): 一级评论:子评论总数更新与查询
- 新增批量查询评论计数的数据库接口及SQL实现 - 优化本地缓存中评论ID失效判断逻辑,修正变量命名 - 增加从Redis中获取评论计数数据的功能,并支持缺失时回源数据库 - 实现评论计数数据异步同步至Redis的逻辑,包括子评论总数和点赞数 - 在消费端增加更新Redis中评论子评论总数的逻辑 - 添加评论计数相关的Redis Key和Field常量定义 - 更新HTTP测试用例中的评论内容和回复ID,验证计数同步功能
This commit is contained in:
@@ -7,6 +7,19 @@ public class RedisKeyConstants {
|
|||||||
*/
|
*/
|
||||||
private static final String HAVE_FIRST_REPLY_COMMENT_KEY_PREFIX = "comment:havaFirstReplyCommentId:";
|
private static final String HAVE_FIRST_REPLY_COMMENT_KEY_PREFIX = "comment:havaFirstReplyCommentId:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash Field: 子评论总数
|
||||||
|
*/
|
||||||
|
public static final String FIELD_CHILD_COMMENT_TOTAL = "childCommentTotal";
|
||||||
|
/**
|
||||||
|
* Hash Field: 点赞总数
|
||||||
|
*/
|
||||||
|
public static final String FIELD_LIKE_TOTAL = "likeTotal";
|
||||||
|
/**
|
||||||
|
* 评论维度计数 Key 前缀
|
||||||
|
*/
|
||||||
|
private static final String COUNT_COMMENT_KEY_PREFIX = "count:comment:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash Field 键:评论总数
|
* Hash Field 键:评论总数
|
||||||
*/
|
*/
|
||||||
@@ -27,6 +40,15 @@ public class RedisKeyConstants {
|
|||||||
*/
|
*/
|
||||||
private static final String COMMENT_DETAIL_KEY_PREFIX = "comment:detail:";
|
private static final String COMMENT_DETAIL_KEY_PREFIX = "comment:detail:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建评论维度计数 Key
|
||||||
|
*
|
||||||
|
* @param commentId 评论 ID
|
||||||
|
* @return 评论维度计数 Key
|
||||||
|
*/
|
||||||
|
public static String buildCountCommentKey(Long commentId) {
|
||||||
|
return COUNT_COMMENT_KEY_PREFIX + commentId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建完整 KEY
|
* 构建完整 KEY
|
||||||
|
|||||||
@@ -102,4 +102,12 @@ public interface CommentDOMapper extends BaseMapper<CommentDO> {
|
|||||||
List<CommentDO> selectChildPageList(@Param("parentId") Long parentId,
|
List<CommentDO> selectChildPageList(@Param("parentId") Long parentId,
|
||||||
@Param("offset") long offset,
|
@Param("offset") long offset,
|
||||||
@Param("pageSize") long pageSize);
|
@Param("pageSize") long pageSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询计数数据
|
||||||
|
*
|
||||||
|
* @param commentIds 评论 ID 列表
|
||||||
|
* @return 计数数据
|
||||||
|
*/
|
||||||
|
List<CommentDO> selectCommentCountByIds(@Param("commentIds") List<Long> commentIds);
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ import com.hanserwei.hannote.comment.biz.constants.RedisKeyConstants;
|
|||||||
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
||||||
import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
|
import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
|
||||||
import com.hanserwei.hannote.comment.biz.domain.mapper.NoteCountDOMapper;
|
import com.hanserwei.hannote.comment.biz.domain.mapper.NoteCountDOMapper;
|
||||||
|
import com.hanserwei.hannote.comment.biz.enums.CommentLevelEnum;
|
||||||
import com.hanserwei.hannote.comment.biz.enums.ResponseCodeEnum;
|
import com.hanserwei.hannote.comment.biz.enums.ResponseCodeEnum;
|
||||||
import com.hanserwei.hannote.comment.biz.model.dto.PublishCommentMqDTO;
|
import com.hanserwei.hannote.comment.biz.model.dto.PublishCommentMqDTO;
|
||||||
import com.hanserwei.hannote.comment.biz.model.vo.*;
|
import com.hanserwei.hannote.comment.biz.model.vo.*;
|
||||||
@@ -37,9 +38,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.springframework.data.redis.core.RedisCallback;
|
import org.springframework.data.redis.core.*;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.core.ZSetOperations;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -212,7 +211,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
|||||||
|
|
||||||
// 先查询本地缓存
|
// 先查询本地缓存
|
||||||
// 新建一个集合用于存储本地缓存中不存在的评论ID
|
// 新建一个集合用于存储本地缓存中不存在的评论ID
|
||||||
List<Long> localeCacheExpiredCommentIds = Lists.newArrayList();
|
List<Long> localCacheExpiredCommentIds = Lists.newArrayList();
|
||||||
|
|
||||||
// 构建本地缓存的key集合
|
// 构建本地缓存的key集合
|
||||||
List<Long> localCacheKeys = commentIdList.stream()
|
List<Long> localCacheKeys = commentIdList.stream()
|
||||||
@@ -225,7 +224,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
|||||||
Map<Long, String> missingData = Maps.newHashMap();
|
Map<Long, String> missingData = Maps.newHashMap();
|
||||||
missingKeys.forEach(key -> {
|
missingKeys.forEach(key -> {
|
||||||
// 记录缓存中不存在的ID
|
// 记录缓存中不存在的ID
|
||||||
localeCacheExpiredCommentIds.add(key);
|
localCacheExpiredCommentIds.add(key);
|
||||||
// 不存在的评论详情,对其Value设置为空字符串
|
// 不存在的评论详情,对其Value设置为空字符串
|
||||||
missingData.put(key, Strings.EMPTY);
|
missingData.put(key, Strings.EMPTY);
|
||||||
});
|
});
|
||||||
@@ -233,7 +232,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 如果localCacheExpiredCommentIds的大小不等于commentIdList的大小,说明本地缓存中有数据
|
// 如果localCacheExpiredCommentIds的大小不等于commentIdList的大小,说明本地缓存中有数据
|
||||||
if (CollUtil.size(localeCacheExpiredCommentIds) != commentIdList.size()) {
|
if (CollUtil.size(localCacheExpiredCommentIds) != commentIdList.size()) {
|
||||||
// 将本地缓存中的评论详情Json转为实体类添加到VO返参集合中
|
// 将本地缓存中的评论详情Json转为实体类添加到VO返参集合中
|
||||||
for (String value : commentIdAndDetailJsonMap.values()) {
|
for (String value : commentIdAndDetailJsonMap.values()) {
|
||||||
if (StringUtils.isBlank(value)) continue;
|
if (StringUtils.isBlank(value)) continue;
|
||||||
@@ -243,12 +242,16 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果localCacheExpiredCommentIds大小为0,说明评论详情全在本地缓存中,直接响应返参
|
// 如果localCacheExpiredCommentIds大小为0,说明评论详情全在本地缓存中,直接响应返参
|
||||||
if (CollUtil.size(localeCacheExpiredCommentIds) == 0) {
|
if (CollUtil.size(localCacheExpiredCommentIds) == 0) {
|
||||||
|
// 计数数据需要从 Redis 中查
|
||||||
|
if (CollUtil.isNotEmpty(commentRspVOS)) {
|
||||||
|
setCommentCountData(commentRspVOS, localCacheExpiredCommentIds);
|
||||||
|
}
|
||||||
return PageResponse.success(commentRspVOS, pageNo, count, pageSize);
|
return PageResponse.success(commentRspVOS, pageNo, count, pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建 MGET 批量查询评论详情的 Key 集合
|
// 构建 MGET 批量查询评论详情的 Key 集合
|
||||||
List<String> commentIdKeys = localeCacheExpiredCommentIds.stream()
|
List<String> commentIdKeys = localCacheExpiredCommentIds.stream()
|
||||||
.map(RedisKeyConstants::buildCommentDetailKey)
|
.map(RedisKeyConstants::buildCommentDetailKey)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@@ -635,4 +638,142 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置评论 VO 的计数
|
||||||
|
*
|
||||||
|
* @param commentRspVOS 返参 VO 集合
|
||||||
|
* @param expiredCommentIds 缓存中已失效的评论 ID 集合
|
||||||
|
*/
|
||||||
|
private void setCommentCountData(List<FindCommentItemRspVO> commentRspVOS,
|
||||||
|
List<Long> expiredCommentIds) {
|
||||||
|
// 准备从评论 Hash 中查询计数 (子评论总数、被点赞数)
|
||||||
|
// 缓存中存在的评论 ID
|
||||||
|
List<Long> notExpiredCommentIds = Lists.newArrayList();
|
||||||
|
|
||||||
|
// 遍历从缓存中解析出的 VO 集合,提取一级、二级评论 ID
|
||||||
|
commentRspVOS.forEach(commentRspVO -> {
|
||||||
|
Long oneLevelCommentId = commentRspVO.getCommentId();
|
||||||
|
notExpiredCommentIds.add(oneLevelCommentId);
|
||||||
|
FindCommentItemRspVO firstCommentVO = commentRspVO.getFirstReplyComment();
|
||||||
|
if (Objects.nonNull(firstCommentVO)) {
|
||||||
|
notExpiredCommentIds.add(firstCommentVO.getCommentId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 已失效的 Hash 评论 ID
|
||||||
|
List<Long> expiredCountCommentIds = Lists.newArrayList();
|
||||||
|
// 构建需要查询的 Hash Key 集合
|
||||||
|
List<String> commentCountKeys = notExpiredCommentIds.stream()
|
||||||
|
.map(RedisKeyConstants::buildCountCommentKey).toList();
|
||||||
|
|
||||||
|
// 使用 RedisTemplate 执行管道批量操作
|
||||||
|
List<Object> results = redisTemplate.executePipelined(new SessionCallback<>() {
|
||||||
|
@Override
|
||||||
|
public Object execute(@NonNull RedisOperations operations) {
|
||||||
|
// 遍历需要查询的评论计数的 Hash 键集合
|
||||||
|
commentCountKeys.forEach(key ->
|
||||||
|
// 在管道中执行 Redis 的 hash.entries 操作
|
||||||
|
// 此操作会获取指定 Hash 键中所有的字段和值
|
||||||
|
operations.opsForHash().entries(key));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 评论 ID - 计数数据字典
|
||||||
|
Map<Long, Map<Object, Object>> commentIdAndCountMap = Maps.newHashMap();
|
||||||
|
// 遍历未过期的评论 ID 集合
|
||||||
|
for (int i = 0; i < notExpiredCommentIds.size(); i++) {
|
||||||
|
// 当前评论 ID
|
||||||
|
Long currCommentId = Long.valueOf(notExpiredCommentIds.get(i).toString());
|
||||||
|
// 从缓存查询结果中,获取对应 Hash
|
||||||
|
Map<Object, Object> hash = (Map<Object, Object>) results.get(i);
|
||||||
|
// 若 Hash 结果为空,说明缓存中不存在,添加到 expiredCountCommentIds 中,保存一下
|
||||||
|
if (CollUtil.isEmpty(hash)) {
|
||||||
|
expiredCountCommentIds.add(currCommentId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 若存在,则将数据添加到 commentIdAndCountMap 中,方便后续读取
|
||||||
|
commentIdAndCountMap.put(currCommentId, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若已过期的计数评论 ID 集合大于 0,说明部分计数数据不在 Redis 缓存中
|
||||||
|
// 需要查询数据库,并将这部分的评论计数 Hash 同步到 Redis 中
|
||||||
|
if (CollUtil.size(expiredCountCommentIds) > 0) {
|
||||||
|
// 查询数据库
|
||||||
|
List<CommentDO> commentDOS = commentDOMapper.selectCommentCountByIds(expiredCountCommentIds);
|
||||||
|
|
||||||
|
commentDOS.forEach(commentDO -> {
|
||||||
|
Integer level = commentDO.getLevel();
|
||||||
|
Map<Object, Object> map = Maps.newHashMap();
|
||||||
|
map.put(RedisKeyConstants.FIELD_LIKE_TOTAL, commentDO.getLikeTotal());
|
||||||
|
// 只有一级评论需要统计子评论总数
|
||||||
|
if (Objects.equals(level, CommentLevelEnum.ONE.getCode())) {
|
||||||
|
map.put(RedisKeyConstants.FIELD_CHILD_COMMENT_TOTAL, commentDO.getChildCommentTotal());
|
||||||
|
}
|
||||||
|
// 统一添加到 commentIdAndCountMap 字典中,方便后续查询
|
||||||
|
commentIdAndCountMap.put(commentDO.getId(), map);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 异步同步到 Redis 中
|
||||||
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
|
redisTemplate.executePipelined(new SessionCallback<>() {
|
||||||
|
@Override
|
||||||
|
public Object execute(RedisOperations operations) {
|
||||||
|
commentDOS.forEach(commentDO -> {
|
||||||
|
// 构建 Hash Key
|
||||||
|
String key = RedisKeyConstants.buildCountCommentKey(commentDO.getId());
|
||||||
|
// 评论级别
|
||||||
|
Integer level = commentDO.getLevel();
|
||||||
|
// 设置 Field 数据
|
||||||
|
Map<String, Long> fieldsMap = Objects.equals(level, CommentLevelEnum.ONE.getCode()) ?
|
||||||
|
Map.of(RedisKeyConstants.FIELD_CHILD_COMMENT_TOTAL, commentDO.getChildCommentTotal(),
|
||||||
|
RedisKeyConstants.FIELD_LIKE_TOTAL, commentDO.getLikeTotal()) : Map.of(RedisKeyConstants.FIELD_LIKE_TOTAL, commentDO.getLikeTotal());
|
||||||
|
// 添加 Hash 数据
|
||||||
|
operations.opsForHash().putAll(key, fieldsMap);
|
||||||
|
|
||||||
|
// 设置随机过期时间 (5小时以内)
|
||||||
|
long expireTime = RandomUtil.randomInt(5 * 60 * 60);
|
||||||
|
operations.expire(key, expireTime, TimeUnit.SECONDS);
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 VO, 设置对应评论的二级评论数、点赞数
|
||||||
|
for (FindCommentItemRspVO commentRspVO : commentRspVOS) {
|
||||||
|
// 评论 ID
|
||||||
|
Long commentId = commentRspVO.getCommentId();
|
||||||
|
|
||||||
|
// 若当前这条评论是从数据库中查询出来的, 则无需设置二级评论数、点赞数,以数据库查询出来的为主
|
||||||
|
if (CollUtil.isNotEmpty(expiredCommentIds)
|
||||||
|
&& expiredCommentIds.contains(commentId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置一级评论的子评论总数、点赞数
|
||||||
|
Map<Object, Object> hash = commentIdAndCountMap.get(commentId);
|
||||||
|
if (CollUtil.isNotEmpty(hash)) {
|
||||||
|
Object childCommentTotalObj = hash.get(RedisKeyConstants.FIELD_CHILD_COMMENT_TOTAL);
|
||||||
|
Long childCommentTotal = Objects.isNull(childCommentTotalObj) ? 0 : Long.parseLong(childCommentTotalObj.toString());
|
||||||
|
Object likeTotalObj = hash.get(RedisKeyConstants.FIELD_LIKE_TOTAL);
|
||||||
|
Long likeTotal = Objects.isNull(likeTotalObj) ? 0 : Long.parseLong(likeTotalObj.toString());
|
||||||
|
commentRspVO.setChildCommentTotal(childCommentTotal);
|
||||||
|
commentRspVO.setLikeTotal(likeTotal);
|
||||||
|
// 最初回复的二级评论
|
||||||
|
FindCommentItemRspVO firstCommentVO = commentRspVO.getFirstReplyComment();
|
||||||
|
if (Objects.nonNull(firstCommentVO)) {
|
||||||
|
Long firstCommentId = firstCommentVO.getCommentId();
|
||||||
|
Map<Object, Object> firstCommentHash = commentIdAndCountMap.get(firstCommentId);
|
||||||
|
if (CollUtil.isNotEmpty(firstCommentHash)) {
|
||||||
|
Long firstCommentLikeTotal = Long.valueOf(firstCommentHash.get(RedisKeyConstants.FIELD_LIKE_TOTAL).toString());
|
||||||
|
firstCommentVO.setLikeTotal(firstCommentLikeTotal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,4 +180,16 @@
|
|||||||
order by id
|
order by id
|
||||||
limit #{offset}, #{pageSize}
|
limit #{offset}, #{pageSize}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCommentCountByIds" resultMap="BaseResultMap" parameterType="list">
|
||||||
|
select id,
|
||||||
|
child_comment_total,
|
||||||
|
like_total,
|
||||||
|
level
|
||||||
|
from t_comment
|
||||||
|
where id in
|
||||||
|
<foreach collection="commentIds" open="(" separator="," close=")" item="commentId">
|
||||||
|
#{commentId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -36,6 +36,25 @@ public class RedisKeyConstants {
|
|||||||
*/
|
*/
|
||||||
public static final String FIELD_COLLECT_TOTAL = "collectTotal";
|
public static final String FIELD_COLLECT_TOTAL = "collectTotal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash Field: 子评论总数
|
||||||
|
*/
|
||||||
|
public static final String FIELD_CHILD_COMMENT_TOTAL = "childCommentTotal";
|
||||||
|
/**
|
||||||
|
* 评论维度计数 Key 前缀
|
||||||
|
*/
|
||||||
|
private static final String COUNT_COMMENT_KEY_PREFIX = "count:comment:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建评论维度计数 Key
|
||||||
|
*
|
||||||
|
* @param commentId 评论ID
|
||||||
|
* @return 评论维度计数 Key
|
||||||
|
*/
|
||||||
|
public static String buildCountCommentKey(Long commentId) {
|
||||||
|
return COUNT_COMMENT_KEY_PREFIX + commentId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建用户维度计数 Key
|
* 构建用户维度计数 Key
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.github.phantomthief.collection.BufferTrigger;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||||
import com.hanserwei.hannote.count.biz.constant.MQConstants;
|
import com.hanserwei.hannote.count.biz.constant.MQConstants;
|
||||||
|
import com.hanserwei.hannote.count.biz.constant.RedisKeyConstants;
|
||||||
import com.hanserwei.hannote.count.biz.domain.mapper.CommentDOMapper;
|
import com.hanserwei.hannote.count.biz.domain.mapper.CommentDOMapper;
|
||||||
import com.hanserwei.hannote.count.biz.enums.CommentLevelEnum;
|
import com.hanserwei.hannote.count.biz.enums.CommentLevelEnum;
|
||||||
import com.hanserwei.hannote.count.biz.model.dto.CountPublishCommentMqDTO;
|
import com.hanserwei.hannote.count.biz.model.dto.CountPublishCommentMqDTO;
|
||||||
@@ -15,6 +16,7 @@ import org.apache.rocketmq.client.producer.SendResult;
|
|||||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.support.MessageBuilder;
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -39,6 +41,9 @@ public class CountNoteChildCommentConsumer implements RocketMQListener<String> {
|
|||||||
@Resource
|
@Resource
|
||||||
private CommentDOMapper commentDOMapper;
|
private CommentDOMapper commentDOMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
private final BufferTrigger<String> bufferTrigger = BufferTrigger.<String>batchBlocking()
|
private final BufferTrigger<String> bufferTrigger = BufferTrigger.<String>batchBlocking()
|
||||||
.bufferSize(50000) // 缓存队列的最大容量
|
.bufferSize(50000) // 缓存队列的最大容量
|
||||||
.batchSize(1000) // 一批次最多聚合 1000 条
|
.batchSize(1000) // 一批次最多聚合 1000 条
|
||||||
@@ -82,6 +87,19 @@ public class CountNoteChildCommentConsumer implements RocketMQListener<String> {
|
|||||||
// 评论数
|
// 评论数
|
||||||
int count = CollUtil.size(entry.getValue());
|
int count = CollUtil.size(entry.getValue());
|
||||||
|
|
||||||
|
// 更新 Redis 缓存中的评论计数数据
|
||||||
|
// 构建 Key
|
||||||
|
String commentCountHashKey = RedisKeyConstants.buildCountCommentKey(parentId);
|
||||||
|
// 判断 Hash 是否存在
|
||||||
|
boolean hasKey = redisTemplate.hasKey(commentCountHashKey);
|
||||||
|
|
||||||
|
// 若 Hash 存在,则更新子评论总数
|
||||||
|
if (hasKey) {
|
||||||
|
// 累加
|
||||||
|
redisTemplate.opsForHash()
|
||||||
|
.increment(commentCountHashKey, RedisKeyConstants.FIELD_CHILD_COMMENT_TOTAL, count);
|
||||||
|
}
|
||||||
|
|
||||||
// 更新一级评论的下级评论总数,进行累加操作
|
// 更新一级评论的下级评论总数,进行累加操作
|
||||||
commentDOMapper.updateChildCommentTotal(parentId, count);
|
commentDOMapper.updateChildCommentTotal(parentId, count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,9 +298,9 @@ Authorization: Bearer {{token}}
|
|||||||
|
|
||||||
{
|
{
|
||||||
"noteId": 1862481582414102549,
|
"noteId": 1862481582414102549,
|
||||||
"content": "这是一条测试同步Redis并更新热度的评论",
|
"content": "这是一条测试同步Redis更新计数的评论",
|
||||||
"imageUrl": "https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg",
|
"imageUrl": "https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg",
|
||||||
"replyCommentId": 8001
|
"replyCommentId": 4002
|
||||||
}
|
}
|
||||||
|
|
||||||
### 批量添加评论
|
### 批量添加评论
|
||||||
|
|||||||
Reference in New Issue
Block a user