Explorar el Código

评论redis优化和pad防重过期时间

xw hace 2 días
padre
commit
f3af7d51bf

+ 1 - 16
fs-admin/src/main/java/com/fs/course/task/VideoTask.java

@@ -18,7 +18,6 @@ import com.qcloud.cos.region.Region;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
@@ -36,7 +35,6 @@ public class VideoTask {
     private static final String FAVORITE_KEY_PREFIX = "favorite:video:";
     private static final String NO_FAVORITE_KEY_PREFIX = "nofavorite:video:";
     private static final String COMMENT_KEY_PREFIX = "comment:video:";
-    private static final String VIDEO_COMMENT_COUNT_KEY_PATTERN = "comment:count:video:*";
     private static final String COMMENT_REPLY_COUNT_KEY_PATTERN = "reply:count:comment:*";
     @Autowired
     private FsUserVideoMapper videoMapper;
@@ -51,8 +49,6 @@ public class VideoTask {
     @Autowired
     private RedisCache redisCache;
     @Autowired
-    private RedisTemplate<String, Object> redisTemplate;
-    @Autowired
     private FsUserCourseVideoMapper courseVideoMapper;
     @Autowired
     private FsCourseRedPacketLogMapper redPacketLogMapper;
@@ -156,18 +152,7 @@ public class VideoTask {
 
     //同步评论数量
     public void syncCommentCountToDatabase() {
-        Set<String> keys = redisTemplate.keys(VIDEO_COMMENT_COUNT_KEY_PATTERN);
-        if (keys != null) {
-            for (String key : keys) {
-                String videoIdStr = key.split(":")[3];
-                Long videoId = Long.parseLong(videoIdStr);
-                Integer commentCount = (Integer) redisTemplate.opsForValue().get(key);
-                if (commentCount != null) {
-                    videoMapper.updateCommentCount(videoId, commentCount);
-                    redisTemplate.delete(key);
-                }
-            }
-        }
+        videoCommentService.syncCommentCountToDatabase();
     }
 
     //同步评论

+ 13 - 0
fs-common/src/main/java/com/fs/common/constant/VideoCommentKeysConstant.java

@@ -0,0 +1,13 @@
+package com.fs.common.constant;
+
+/**
+ * 短视频评论数 Redis key(与 {@link com.fs.course.utils.VideoCommentCountRedisUtil} 配合使用)
+ */
+public final class VideoCommentKeysConstant {
+
+    private VideoCommentKeysConstant() {
+    }
+
+    public static final String VIDEO_COMMENT_COUNT_PREFIX = "comment:count:video:";
+    public static final String VIDEO_COMMENT_COUNT_INDEX = "comment:count:video:index";
+}

+ 4 - 0
fs-common/src/main/java/com/fs/common/utils/redis/RedisActiveKeyIndexRepairService.java

@@ -2,6 +2,7 @@ package com.fs.common.utils.redis;
 
 import com.fs.common.constant.CourseWatchKeysConstant;
 import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.constant.VideoCommentKeysConstant;
 import com.fs.common.core.redis.RedisCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -109,6 +110,9 @@ public class RedisActiveKeyIndexRepairService {
         targets.add(new IndexRepairTarget("h5wxDuration",
                 CourseWatchKeysConstant.H5_WX_DURATION_PREFIX + "*",
                 CourseWatchKeysConstant.H5_WX_DURATION_INDEX));
+        targets.add(new IndexRepairTarget("videoCommentCount",
+                VideoCommentKeysConstant.VIDEO_COMMENT_COUNT_PREFIX + "*",
+                VideoCommentKeysConstant.VIDEO_COMMENT_COUNT_INDEX));
         return targets;
     }
 

+ 1 - 1
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -223,7 +223,7 @@ public class SendMsg {
                 log.error("{}已有发送:{}, :{}", qwUser.getQwUserName(), qwSopLogs.getId(), time);
                 continue;
             }
-            redisCache.setCacheObject(key, System.currentTimeMillis(), 24, TimeUnit.HOURS);
+            redisCache.setCacheObject(key, System.currentTimeMillis(), 1, TimeUnit.HOURS);
             List<QwPushCount> pushCountList = qwPushCountMapper.selectQwPushCountLists();
             Map<Integer, List<QwPushCount>> pushMap = pushCountList.stream().collect(Collectors.groupingBy(QwPushCount::getType));
             // 循环发送消息里面的每一条消息

+ 5 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserVideoCommentService.java

@@ -80,4 +80,9 @@ public interface IFsUserVideoCommentService
 
     void syncRepliesToDatabase();
 
+    /**
+     * 将 Redis 中待同步的视频评论数写入数据库(使用索引,避免 KEYS)
+     */
+    void syncCommentCountToDatabase();
+
 }

+ 46 - 8
fs-service/src/main/java/com/fs/course/service/impl/FsUserVideoCommentServiceImpl.java

@@ -20,8 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsUserVideoCommentMapper;
+import com.fs.course.mapper.FsUserVideoMapper;
 import com.fs.course.domain.FsUserVideoComment;
 import com.fs.course.service.IFsUserVideoCommentService;
+import com.fs.course.utils.VideoCommentCountRedisUtil;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -48,6 +50,12 @@ public class FsUserVideoCommentServiceImpl implements IFsUserVideoCommentService
     @Autowired
     private FsUserMapper fsUserMapper;
 
+    @Autowired
+    private FsUserVideoMapper fsUserVideoMapper;
+
+    @Autowired
+    private VideoCommentCountRedisUtil videoCommentCountRedisUtil;
+
     private static final String COMMENT_LIST_KEY_PREFIX = "comment:list:video:";
     private static final String COMMENT_HASH_KEY_PREFIX = "comment:hash:video:";
     private static final String REPLY_LIST_KEY_PREFIX = "reply:list:comment:";
@@ -58,8 +66,6 @@ public class FsUserVideoCommentServiceImpl implements IFsUserVideoCommentService
     private static final String COMMENT_LIKE_KEY_PREFIX = "like:comment:";
     private static final String COMMENT_LIKE_COUNT_KEY_PREFIX = "likecount:comment:";
     private static final String COMMENT_REPLY_COUNT_KEY_PREFIX = "reply:count:comment:";
-    private static final String VIDEO_COMMENT_COUNT_KEY_PREFIX = "comment:count:video:";
-
     /**
      * 查询课堂视频评论
      *
@@ -170,12 +176,8 @@ public class FsUserVideoCommentServiceImpl implements IFsUserVideoCommentService
 //        redisTemplate.expire(listKey, 1, TimeUnit.DAYS);
 //        redisTemplate.expire(hashKey, 1, TimeUnit.DAYS);
 //
-//        // 增加视频的评论数
-//        String videoCommentCountKey = VIDEO_COMMENT_COUNT_KEY_PREFIX + param.getVideoId();
-//        if (redisTemplate.opsForValue().get(videoCommentCountKey) == null) {
-//            redisTemplate.opsForValue().set(videoCommentCountKey, 0);
-//        }
-//        redisTemplate.opsForValue().increment(videoCommentCountKey, 1);
+//        // 增加视频的评论数(须走 VideoCommentCountRedisUtil 以登记索引)
+//        videoCommentCountRedisUtil.incrementCommentCount(param.getVideoId());
 //        return R.ok().put("data", comment);
 //    }
 
@@ -584,4 +586,40 @@ public class FsUserVideoCommentServiceImpl implements IFsUserVideoCommentService
             }
         }
     }
+
+    @Override
+    public void syncCommentCountToDatabase() {
+        Set<String> keys = videoCommentCountRedisUtil.listKeys();
+        if (keys == null || keys.isEmpty()) {
+            return;
+        }
+        for (String key : keys) {
+            try {
+                String videoIdStr = key.split(":")[3];
+                Long videoId = Long.parseLong(videoIdStr);
+                Object value = redisTemplate.opsForValue().get(key);
+                Integer commentCount = toIntegerCount(value);
+                if (commentCount != null) {
+                    fsUserVideoMapper.updateCommentCount(videoId, commentCount);
+                    redisTemplate.delete(key);
+                    videoCommentCountRedisUtil.untrack(key);
+                }
+            } catch (Exception e) {
+                // 单条失败不影响其余 key
+            }
+        }
+    }
+
+    private static Integer toIntegerCount(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Long) {
+            return ((Long) value).intValue();
+        }
+        return null;
+    }
 }

+ 73 - 0
fs-service/src/main/java/com/fs/course/utils/VideoCommentCountRedisUtil.java

@@ -0,0 +1,73 @@
+package com.fs.course.utils;
+
+import com.fs.common.constant.VideoCommentKeysConstant;
+import com.fs.common.core.redis.RedisCache;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 视频评论数 Redis 索引,避免 KEYS comment:count:video:* 全库扫描。
+ */
+@Component
+public class VideoCommentCountRedisUtil {
+
+    public static final String COUNT_PREFIX = VideoCommentKeysConstant.VIDEO_COMMENT_COUNT_PREFIX;
+    public static final String COUNT_INDEX = VideoCommentKeysConstant.VIDEO_COMMENT_COUNT_INDEX;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    public static String commentCountKey(Long videoId) {
+        return COUNT_PREFIX + videoId;
+    }
+
+    public void track(String cacheKey) {
+        redisCache.redisTemplate.opsForSet().add(COUNT_INDEX, cacheKey);
+    }
+
+    public void track(Long videoId) {
+        track(commentCountKey(videoId));
+    }
+
+    public void untrack(String cacheKey) {
+        redisCache.redisTemplate.opsForSet().remove(COUNT_INDEX, cacheKey);
+    }
+
+    public void untrack(Long videoId) {
+        untrack(commentCountKey(videoId));
+    }
+
+    /**
+     * 评论数 +1 并登记索引(写入 Redis 时调用,供定时同步扫索引)
+     */
+    public void incrementCommentCount(Long videoId) {
+        String cacheKey = commentCountKey(videoId);
+        redisTemplate.opsForValue().increment(cacheKey, 1);
+        track(cacheKey);
+    }
+
+    public Set<String> listKeys() {
+        Set<Object> members = redisCache.redisTemplate.opsForSet().members(COUNT_INDEX);
+        if (members == null || members.isEmpty()) {
+            return Collections.emptySet();
+        }
+        Set<String> result = new HashSet<>(members.size());
+        for (Object member : members) {
+            String cacheKey = member.toString();
+            if (Boolean.TRUE.equals(redisCache.redisTemplate.hasKey(cacheKey))) {
+                result.add(cacheKey);
+            } else {
+                untrack(cacheKey);
+            }
+        }
+        return result;
+    }
+}

+ 1 - 17
fs-user-app/src/main/java/com/fs/app/controller/VideoTestController.java

@@ -19,7 +19,6 @@ import com.fs.sop.domain.QwSopLogs;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
@@ -37,7 +36,6 @@ public class VideoTestController{
     private static final String FAVORITE_KEY_PREFIX = "favorite:video:";
     private static final String NO_FAVORITE_KEY_PREFIX = "nofavorite:video:";
     private static final String COMMENT_KEY_PREFIX = "comment:video:";
-    private static final String VIDEO_COMMENT_COUNT_KEY_PATTERN = "comment:count:video:*";
     private static final String COMMENT_REPLY_COUNT_KEY_PATTERN = "reply:count:comment:*";
     @Autowired
     private FsUserVideoMapper videoMapper;
@@ -51,9 +49,6 @@ public class VideoTestController{
     private FsUserVideoCommentMapper videoCommentMapper;
     @Autowired
     private RedisCache redisCache;
-    @Autowired
-    private RedisTemplate<String, Object> redisTemplate;
-
     //同步点赞到数据库
     @ApiOperation("同步点赞")
     @GetMapping("/syncLikes")
@@ -144,18 +139,7 @@ public class VideoTestController{
     //同步评论数量
     @GetMapping("/syncCommentCount")
     public void syncCommentCountToDatabase() {
-        Set<String> keys = redisTemplate.keys(VIDEO_COMMENT_COUNT_KEY_PATTERN);
-        if (keys != null) {
-            for (String key : keys) {
-                String videoIdStr = key.split(":")[3];
-                Long videoId = Long.parseLong(videoIdStr);
-                Integer commentCount = (Integer) redisTemplate.opsForValue().get(key);
-                if (commentCount != null) {
-                    videoMapper.updateCommentCount(videoId, commentCount);
-                    redisTemplate.delete(key);
-                }
-            }
-        }
+        videoCommentService.syncCommentCountToDatabase();
     }
 
     @Autowired