当前位置: 首页 > wzjs >正文

游戏网站设计论文济宁推广

游戏网站设计论文,济宁推广,网站建设报价东莞,能发朋友圈的网站建设广告语第一版 获取视频信息使用旁路缓存 当视频信息存在缓存中时(命中),直接从缓存中获取。不存在缓存中时,先从数据库中查出对应的信息,写入缓存后再放回数据。 //获取视频详细信息RequestMapping("/getVideoInfo&q…

第一版

获取视频信息使用旁路缓存

  • 当视频信息存在缓存中时(命中),直接从缓存中获取。
  • 不存在缓存中时,先从数据库中查出对应的信息,写入缓存后再放回数据。
//获取视频详细信息@RequestMapping("/getVideoInfo")public ResponseVO getVideoInfo(@NotEmpty String videoId) {//旁路缓存模式,先从缓存中拿VideoInfo videoInfo = redisComponent.getVideoInfoDetail(videoId);if(videoInfo == null){//缓存中不存在就从数据库中取videoInfo = videoInfoService.getVideoInfoByVideoId(videoId);}if(videoInfo==null){throw new BusinessException(ResponseCodeEnum.CODE_404);}//将视频信息保存到缓存中redisComponent.saveVideoInfoDeTail(videoInfo);//获取当前用户对应的点赞和投币信息TokenUserInfoDto userInfoDto = getTokenUserInfoDto();List<UserAction> userActionList = new ArrayList<>();if(userInfoDto!=null){UserActionQuery actionQuery = new UserActionQuery();actionQuery.setVideoId(videoId);actionQuery.setUserId(userInfoDto.getUserId());//查询视频对应用户的点赞投币收藏信息actionQuery.setActionTypeArray(new Integer[]{UserActionTypeEnum.VIDEO_LIKE.getType(),UserActionTypeEnum.VIDEO_COLLECT.getType(),UserActionTypeEnum.VIDEO_COIN.getType(),});userActionList = userActionService.findListByParam(actionQuery);}VideoInfoResultVo resultVo = new VideoInfoResultVo();//设置用户的点赞投币收藏信息resultVo.setUserActionList(userActionList);resultVo.setVideoInfo(CopyTools.copy(videoInfo, VideoInfoVo.class));return getSuccessResponseVO(resultVo);}

用户点赞、收藏使用异步缓存写入

在进行更新视频点赞、收藏数量等信息时,并非直接修改数据库,而是先修改缓存中的数据,再利用消息队列,或定时任务等方式,将缓存中的数据更新到数据库

@Override@Transactional(rollbackFor = Exception.class)public void saveAction(UserAction bean) {//旁路缓存模式,想从缓存中拿VideoInfo videoInfo = redisComponent.getVideoInfoDetail(bean.getVideoId());if(videoInfo == null){//缓存中不存在就从数据库中取videoInfo = videoInfoMapper.selectByVideoId(bean.getVideoId());}if(videoInfo==null){throw new BusinessException(ResponseCodeEnum.CODE_404);}//设置视频对应的用户idbean.setVideoUserId(videoInfo.getUserId());//获得对应的用户行为(点赞,收藏,投币,评论点赞)UserActionTypeEnum actionTypeEnum = UserActionTypeEnum.getByType(bean.getActionType());if(actionTypeEnum==null){throw new BusinessException(ResponseCodeEnum.CODE_600);}//从数据库中根据视频id,评论id(若为评论点赞的话),行为类型,和用户行为来查询对应的行为记录UserAction dbAction = userActionMapper.selectByVideoIdAndCommentIdAndActionTypeAndUserId(bean.getVideoId(),bean.getCommentId(), bean.getActionType(), bean.getUserId());bean.setActionTime(new Date());switch (actionTypeEnum){//点赞和收藏case VIDEO_LIKE:case VIDEO_COLLECT://若存在点赞和收藏的记录,则取消点赞或收藏if(dbAction!=null){userActionMapper.deleteByActionId(dbAction.getActionId());}else{//添加对应的行为记录userActionMapper.insert(bean);}//若之前点过赞或收藏过则改变数量为-1,否则为1Integer changeCount = dbAction == null? Constants.ONE:-Constants.ONE;//更新视频对应的点赞或收藏信息if (actionTypeEnum.getType() == 2){Integer likeCount = videoInfo.getLikeCount();likeCount += changeCount;videoInfo.setLikeCount(likeCount);}else{Integer collectCount = videoInfo.getCollectCount();collectCount += changeCount;videoInfo.setCollectCount(collectCount);}//videoInfoMapper.updateCountInfo(bean.getVideoId(),actionTypeEnum.getField(),changeCount);if(actionTypeEnum == UserActionTypeEnum.VIDEO_COLLECT){//更新es的收藏数量esSearchComponent.updateDocCount(videoInfo.getVideoId(), SearchOrderTypeEnum.VIDEO_COLLECT.getField(), changeCount);}break;//投币case VIDEO_COIN:if (videoInfo.getUserId().equals(bean.getUserId())) {throw new BusinessException("UP主不能给自己投币");}if (dbAction != null) {throw new BusinessException("对本稿件的投币枚数已用完");}//更新当前用户的硬币数量, 返回的整数即为成功更新的行数Integer updateCoinCountInfo = userInfoMapper.updateCoinCountInfo(bean.getUserId(), -bean.getActionCount());//未成功更新说明硬币数量不够if(updateCoinCountInfo == 0){throw new BusinessException("硬币数量不足");}updateCoinCountInfo = userInfoMapper.updateCoinCountInfo(bean.getVideoUserId(), bean.getActionCount());//并发操作,数据库行上锁if(updateCoinCountInfo == 0){throw new BusinessException("投币失败");}//添加对应的行为记录userActionMapper.insert(bean);//更新视频对应的点赞或收藏信息//videoInfoMapper.updateCountInfo(bean.getVideoId(),actionTypeEnum.getField(), bean.getActionCount());break;}//将视频信息保存到缓存中redisComponent.saveVideoInfoDeTail(videoInfo);}
使用定时任务同步缓存与数据库
@Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行一次public void updateCachePeriodically() {try {// 从Redis中批量获取视频信息Map<String, VideoInfo> videoInfoBatch = redisComponent.getVideoInfoBatch();if (videoInfoBatch == null || videoInfoBatch.isEmpty()) {log.info("No video info found in Redis cache.");return;}// 提取视频信息列表List<VideoInfo> videoInfoList = new ArrayList<>(videoInfoBatch.values());// 批量更新数据库videoInfoService.addOrUpdateBatch(videoInfoList);log.info("Successfully updated {} video infos in the database.", videoInfoList.size());} catch (Exception e) {log.error("Error occurred during periodic cache update", e);}}

在你的第一版实现中,已经很好地结合了旁路缓存(视频基本信息)和异步写入缓存(点赞、收藏、播放量等高频修改信息)。以下是对你现有实现的分析和进一步优化的建议,以确保数据一致性和系统的高效性。


现有实现的优点

  1. 旁路缓存模式

    • 视频基本信息通过旁路缓存模式实现,减少了数据库的读取压力。
    • 缓存未命中时,从数据库加载数据并更新缓存,保证了数据的最终一致性。
  2. 异步写入缓存

    • 点赞、收藏等高频修改信息直接更新缓存,然后通过定时任务批量同步到数据库,减少了数据库的写入压力。
    • 使用消息队列或定时任务确保数据最终一致性。
  3. 定时任务同步

    • 定时任务定期从缓存中获取数据并同步到数据库,避免了实时同步带来的性能开销。

潜在问题和优化建议

1. 缓存穿透问题

在旁路缓存模式下,如果视频信息不存在,每次请求都会直接查询数据库,可能导致数据库压力过大。

优化建议

  • 在缓存中存储一个空对象或特殊标记(如 nullempty),表示该 videoId 对应的视频信息不存在。
  • 示例:
    if (videoInfo == null) {videoInfo = videoInfoService.getVideoInfoByVideoId(videoId);if (videoInfo == null) {redisComponent.saveVideoInfoDetail(new VideoInfo(videoId, "empty"), 5, TimeUnit.MINUTES); // 存储空对象,设置较短的过期时间throw new BusinessException(ResponseCodeEnum.CODE_404);}
    }
    
2. 缓存更新冲突

在多线程环境下,多个请求可能同时从数据库加载数据并更新缓存,导致缓存写入冲突。

优化建议

  • 使用分布式锁(如 Redisson)控制缓存的写入操作。
  • 示例:
    if (videoInfo == null) {redisComponent.lockVideoInfo(videoId); // 加锁videoInfo = videoInfoService.getVideoInfoByVideoId(videoId);if (videoInfo == null) {throw new BusinessException(ResponseCodeEnum.CODE_404);}redisComponent.saveVideoInfoDetail(videoInfo);redisComponent.unlockVideoInfo(videoId); // 解锁
    }
    
3. 数据一致性问题

在异步写入缓存模式下,缓存数据可能因为服务故障而丢失,导致数据不一致。

优化建议

  • 消息队列:将每次用户行为(如点赞、收藏)记录到消息队列中,后台消费者定期从队列中读取行为记录并更新缓存和数据库。
  • 持久化更新日志:在更新缓存时,将更新操作记录到持久化存储(如日志文件或数据库),以便在缓存服务故障时恢复数据。
  • 示例:
    // 发送消息到队列
    messageQueue.send(new VideoActionMessage(bean.getVideoId(), actionTypeEnum, changeCount));
    
4. 定时任务的优化

定时任务每次同步所有缓存数据,可能导致性能问题,尤其是在缓存数据量较大时。

优化建议

  • 增量更新:只同步缓存中发生变化的数据,而不是全量同步。
  • 设置缓存过期时间:为缓存中的高频修改信息设置较短的过期时间(如 5 分钟),确保数据不会长时间不一致。
  • 示例:
    @Scheduled(cron = "0 0/5 * * * ?")
    public void updateCachePeriodically() {List<VideoMetrics> changedMetrics = redisComponent.getChangedMetrics();if (changedMetrics == null || changedMetrics.isEmpty()) {log.info("No changed video metrics found in Redis cache.");return;}videoInfoService.updateMetricsBatch(changedMetrics);log.info("Successfully updated {} video metrics in the database.", changedMetrics.size());
    }
    
5. 数据库更新的原子性

在更新数据库时,可能存在并发问题,导致数据不一致。

优化建议

  • 使用数据库事务(@Transactional)确保更新操作的原子性。
  • 在更新数据库时,使用乐观锁或悲观锁,避免并发冲突。

优化后的代码示例

获取视频信息
@RequestMapping("/getVideoInfo")
public ResponseVO getVideoInfo(@NotEmpty String videoId) {VideoInfo videoInfo = redisComponent.getVideoInfoDetail(videoId);if (videoInfo == null) {redisComponent.lockVideoInfo(videoId); // 加锁videoInfo = videoInfoService.getVideoInfoByVideoId(videoId);if (videoInfo == null) {redisComponent.saveVideoInfoDetail(new VideoInfo(videoId, "empty"), 5, TimeUnit.MINUTES); // 存储空对象redisComponent.unlockVideoInfo(videoId); // 解锁throw new BusinessException(ResponseCodeEnum.CODE_404);}redisComponent.saveVideoInfoDetail(videoInfo);redisComponent.unlockVideoInfo(videoId); // 解锁}// 获取用户行为信息TokenUserInfoDto userInfoDto = getTokenUserInfoDto();List<UserAction> userActionList = new ArrayList<>();if (userInfoDto != null) {UserActionQuery actionQuery = new UserActionQuery();actionQuery.setVideoId(videoId);actionQuery.setUserId(userInfoDto.getUserId());actionQuery.setActionTypeArray(new Integer[]{UserActionTypeEnum.VIDEO_LIKE.getType(),UserActionTypeEnum.VIDEO_COLLECT.getType(),UserActionTypeEnum.VIDEO_COIN.getType()});userActionList = userActionService.findListByParam(actionQuery);}VideoInfoResultVo resultVo = new VideoInfoResultVo();resultVo.setUserActionList(userActionList);resultVo.setVideoInfo(CopyTools.copy(videoInfo, VideoInfoVo.class));return getSuccessResponseVO(resultVo);
}
用户行为处理
@Override
@Transactional(rollbackFor = Exception.class)
public void saveAction(UserAction bean) {VideoInfo videoInfo = redisComponent.getVideoInfoDetail(bean.getVideoId());if (videoInfo == null) {videoInfo = videoInfoMapper.selectByVideoId(bean.getVideoId());if (videoInfo == null) {throw new BusinessException(ResponseCodeEnum.CODE_404);}}bean.setVideoUserId(videoInfo.getUserId());UserActionTypeEnum actionTypeEnum = UserActionTypeEnum.getByType(bean.getActionType());if (actionTypeEnum == null) {throw new BusinessException(ResponseCodeEnum.CODE_600);}UserAction dbAction = userActionMapper.selectByVideoIdAndCommentIdAndActionTypeAndUserId(bean.getVideoId(), bean.getCommentId(), bean.getActionType(), bean.getUserId());bean.setActionTime(new Date());switch (actionTypeEnum) {case VIDEO_LIKE:case VIDEO_COLLECT:if (dbAction != null) {userActionMapper.deleteByActionId(dbAction.getActionId());} else {userActionMapper.insert(bean);}Integer changeCount = dbAction == null ? Constants.ONE : -Constants.ONE;updateVideoMetrics(bean.getVideoId(), actionTypeEnum, changeCount);break;case VIDEO_COIN:// 投币逻辑break;}redisComponent.saveVideoInfoDetail(videoInfo); // 更新缓存messageQueue.send(new VideoActionMessage(bean.getVideoId(), actionTypeEnum, changeCount)); // 发送消息到队列
}
更新视频指标
private void updateVideoMetrics(String videoId, UserActionTypeEnum actionType, Integer changeCount) {VideoMetrics metrics = redisComponent.getVideoMetrics(videoId);if (metrics == null) {metrics = new VideoMetrics(videoId);}switch (actionType) {case VIDEO_LIKE:metrics.setLikeCount(metrics.getLikeCount() + changeCount);break;case VIDEO_COLLECT:metrics.setCollectCount(metrics.getCollectCount() + changeCount);break;}redisComponent.saveVideoMetrics(metrics);
}
定时任务同步
@Scheduled(cron = "0 0/5 * * * ?")
public void updateCachePeriodically() {List<VideoMetrics> changedMetrics = redisComponent.getChangedMetrics();if (changedMetrics == null || changedMetrics.isEmpty()) {log.info("No changed video metrics found in Redis cache.");return;}videoInfoService.updateMetricsBatch(changedMetrics);log.info("Successfully updated {} video metrics in the database.", changedMetrics.size());
}

总结

通过上述优化,你的实现能够更好地解决以下问题:

  1. 缓存穿透:通过存储空对象避免无效的数据库查询。
  2. 缓存更新冲突:使用分布式锁确保缓存更新的线程安全。
  3. 数据一致性:结合消息队列和定时任务确保缓存与数据库的最终一致性。
  4. 性能优化:通过增量更新和缓存过期时间减少定时任务的压力。

这种设计既保证了系统的高性能,又确保了数据的一致性。

第二版:使用 Redis Hash 和 Set 实现视频缓存和用户行为管理

  • 将视频的播放量,点赞,收藏信息独立出来,使用Hash进行缓存。
  • 定时任务只更新有变动的视频数据
  • 实现用户点赞高亮信息从SET中获取
1. 视频信息的缓存和数据库同步

获取视频信息

@RequestMapping("/getVideoInfo")
public ResponseVO getVideoInfo(@NotEmpty String videoId) {// 从缓存中获取视频基本信息VideoInfo videoInfo = redisComponent.getVideoInfoDetail(videoId);if (videoInfo == null) {// 缓存中不存在,从数据库中获取videoInfo = videoInfoService.getVideoInfoByVideoId(videoId);if (videoInfo == null) {throw new BusinessException(ResponseCodeEnum.CODE_404);}// 将视频信息保存到缓存中redisComponent.saveVideoInfoDetail(videoInfo);}// 获取当前用户对应的点赞和投币信息TokenUserInfoDto userInfoDto = getTokenUserInfoDto();List<UserAction> userActionList = new ArrayList<>();if (userInfoDto != null) {UserActionQuery actionQuery = new UserActionQuery();actionQuery.setVideoId(videoId);actionQuery.setUserId(userInfoDto.getUserId());actionQuery.setActionTypeArray(new Integer[]{UserActionTypeEnum.VIDEO_LIKE.getType(),UserActionTypeEnum.VIDEO_COLLECT.getType(),UserActionTypeEnum.VIDEO_COIN.getType()});userActionList = userActionService.findListByParam(actionQuery);}// 构建返回结果VideoInfoResultVo resultVo = new VideoInfoResultVo();resultVo.setUserActionList(userActionList);resultVo.setVideoInfo(CopyTools.copy(videoInfo, VideoInfoVo.class));return getSuccessResponseVO(resultVo);
}

Set 的使用

  • 用户点赞信息:使用 Redis 的 Set 数据结构存储每个视频的点赞用户 ID。Set 的特点是无序且唯一,非常适合存储点赞用户信息,因为每个用户只能点赞一次。
  • 点赞操作:通过 redisComponent.likeVideo(videoId, userId) 将用户 ID 添加到 Set 中。
  • 取消点赞操作:通过 redisComponent.unlikeVideo(videoId, userId) 从 Set 中移除用户 ID。
  • 检查是否点赞:通过 redisComponent.hasUserLiked(videoId, userId) 检查用户 ID 是否在 Set 中。

Hash 的使用

  • 视频指标信息:使用 Redis 的 Hash 数据结构存储视频的播放量、点赞数、收藏数等信息。Hash 的特点是键值对存储,非常适合存储多个字段。
  • 更新视频指标:通过 redisComponent.updateVideoMetrics(videoId, type, num) 更新视频的某个指标。
2. 用户行为处理

保存用户行为

@Override
@Transactional(rollbackFor = Exception.class)
public void saveAction(UserAction bean) {// 获取视频基本信息VideoInfo videoInfo = videoInfoMapper.selectByVideoId(bean.getVideoId());if (videoInfo == null) {throw new BusinessException(ResponseCodeEnum.CODE_404);}// 设置视频对应的用户IDbean.setVideoUserId(videoInfo.getUserId());// 获取用户行为类型UserActionTypeEnum actionTypeEnum = UserActionTypeEnum.getByType(bean.getActionType());if (actionTypeEnum == null) {throw new BusinessException(ResponseCodeEnum.CODE_600);}// 查询数据库中对应的行为记录UserAction dbAction = userActionMapper.selectByVideoIdAndCommentIdAndActionTypeAndUserId(bean.getVideoId(),bean.getCommentId(),bean.getActionType(),bean.getUserId());bean.setActionTime(new Date());switch (actionTypeEnum) {case VIDEO_LIKE:handleLikeAction(videoInfo, bean, dbAction);break;case VIDEO_COLLECT:handleCollectAction(videoInfo, bean, dbAction);break;case VIDEO_COIN:handleCoinAction(videoInfo, bean, dbAction);break;}
}

处理点赞行为

private void handleLikeAction(VideoInfo videoInfo, UserAction bean, UserAction dbAction) {String videoId = bean.getVideoId();String userId = bean.getUserId();boolean hasLiked = redisComponent.hasUserLiked(videoId, userId);if (hasLiked) {// 取消点赞redisComponent.unlikeVideo(videoId, userId);updateVideoMetrics(videoId, Constants.VIDEO_LIKE_NUM, -1);} else {// 点赞redisComponent.likeVideo(videoId, userId);updateVideoMetrics(videoId, Constants.VIDEO_LIKE_NUM, 1);}
}

处理收藏行为

private void handleCollectAction(VideoInfo videoInfo, UserAction bean, UserAction dbAction) {String videoId = bean.getVideoId();if (dbAction != null) {userActionMapper.deleteByActionId(dbAction.getActionId());updateVideoMetrics(videoId, Constants.VIDEO_COLLECT_NUM, -1);} else {userActionMapper.insert(bean);updateVideoMetrics(videoId, Constants.VIDEO_COLLECT_NUM, 1);}
}

处理投币行为

private void handleCoinAction(VideoInfo videoInfo, UserAction bean, UserAction dbAction) {String videoId = bean.getVideoId();String userId = bean.getUserId();if (videoInfo.getUserId().equals(userId)) {throw new BusinessException("UP主不能给自己投币");}if (dbAction != null) {throw new BusinessException("对本稿件的投币枚数已用完");}Integer updateCoinCountInfo = userInfoMapper.updateCoinCountInfo(userId, -bean.getActionCount());if (updateCoinCountInfo == 0) {throw new BusinessException("硬币数量不足");}updateCoinCountInfo = userInfoMapper.updateCoinCountInfo(videoInfo.getUserId(), bean.getActionCount());if (updateCoinCountInfo == 0) {throw new BusinessException("投币失败");}userActionMapper.insert(bean);updateVideoMetrics(videoId, Constants.VIDEO_COIN_NUM, bean.getActionCount());
}
3. 定时任务同步缓存到数据库
@Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行一次
public void updateCachePeriodically() {Set<String> keySet = redisUtils.getByKeyPrefix(Constants.VIDEO_METRICS_KEY);List<String> keyList = new ArrayList<>(keySet);if (keyList.isEmpty()) {return;}for (String key : keyList) {// 获取缓存中的视频指标信息Map<String, Integer> videoMetrics = redisComponent.getAllVideoMetrics(key);String videoId = key.substring(key.lastIndexOf(":") + 1);// 更新数据库VideoInfo videoInfo = new VideoInfo();videoInfo.setVideoId(videoId);videoInfo.setLikeCount(videoMetrics.getOrDefault(Constants.VIDEO_LIKE_NUM, 0));videoInfo.setCollectCount(videoMetrics.getOrDefault(Constants.VIDEO_COLLECT_NUM, 0));videoInfo.setCoinCount(videoMetrics.getOrDefault(Constants.VIDEO_COIN_NUM, 0));videoInfoService.updateVideoMetrics(videoInfo);// 删除旧的缓存redisComponent.deleteAllVideoMetrics(videoId);redisComponent.deleteVideoInfoDeTail(videoId);log.info("数据更新成功");}
}

Set 的使用

  • 用户点赞信息:通过 redisComponent.hasUserLiked(videoId, userId) 检查用户是否点赞,通过 redisComponent.likeVideo(videoId, userId) 添加点赞信息,通过 redisComponent.unlikeVideo(videoId, userId) 删除点赞信息。

Hash 的使用

  • 视频指标信息:通过 redisComponent.updateVideoMetrics(videoId, type, num) 更新视频的某个指标,通过 redisComponent.getAllVideoMetrics(key) 获取视频的所有指标信息。
4. RedisComponent 实现
@Component
public class RedisComponent {@Autowiredprivate RedisUtils redisUtils;// 获取视频详细信息public VideoInfo getVideoInfoDetail(String videoId) {return (VideoInfo) redisUtils.get(Constants.VIDEO_DETAIL_KEY + videoId);}// 保存视频详细信息public void saveVideoInfoDeTail(VideoInfo videoInfo) {redisUtils.setex(Constants.VIDEO_DETAIL_KEY + videoInfo.getVideoId(), videoInfo, Constants.TIME_SECONDS_DAY);}// 删除视频详细信息public void deleteVideoInfoDeTail(String videoId) {redisUtils.delete(Constants.VIDEO_DETAIL_KEY + videoId);}// 批量获取视频信息public Map<String, VideoInfo> getVideoInfoBatch() {Map<String, VideoInfo> batch = redisUtils.getBatch(Constants.VIDEO_DETAIL_KEY);return batch;}// 用户点赞操作public void likeVideo(String videoId, String userId) {String key = Constants.VIDEO_LIKEUSERS_KEY + videoId;redisUtils.addSet(key, userId);}// 用户取消点赞操作public void unlikeVideo(String videoId, String userId) {String key = Constants.VIDEO_LIKEUSERS_KEY + videoId;redisUtils.removeSet(key, userId);}// 检查用户是否点赞public boolean hasUserLiked(String videoId, String userId) {String key = Constants.VIDEO_LIKEUSERS_KEY + videoId;return redisUtils.hasMemberSet(key, userId);}// 更新视频相关数量信息public void updateVideoMetrics(String videoId, String type, Integer num) {String key = Constants.VIDEO_METRICS_KEY + videoId;redisUtils.putHash(key, type, num);}// 获取缓存中的视频的所有信息public Map<String, Integer> getAllVideoMetrics(String key) {return redisUtils.getAllHash(key);}// 删除缓存中的视频的所有信息public void deleteAllVideoMetrics(String videoId) {redisUtils.delete(Constants.VIDEO_METRICS_KEY + videoId);}
}

Set 的使用

  • 用户点赞信息:使用 Redis 的 Set 数据结构存储每个视频的点赞用户 ID。Set 的特点是无序且唯一,非常适合存储点赞用户信息,因为每个用户只能点赞一次。
  • 点赞操作:通过 redisUtils.addSet(key, userId) 将用户 ID 添加到 Set 中。
  • 取消点赞操作:通过 redisUtils.removeSet(key, userId) 从 Set 中移除用户 ID。
  • 检查是否点赞:通过 redisUtils.hasMemberSet(key, userId) 检查用户 ID 是否在 Set 中。

Hash 的使用

  • 视频指标信息:使用 Redis 的 Hash 数据结构存储视频的播放量、点赞数、收藏数等信息。Hash 的特点是键值对存储,非常适合存储多个字段。
  • 更新视频指标:通过 redisUtils.putHash(key, type, num) 更新视频的某个指标。
  • 获取视频指标:通过 redisUtils.getAllHash(key) 获取视频的所有指标信息。
5. Constants 类
public class Constants {// Redis Key 前缀public static final String VIDEO_DETAIL_KEY = "video:info:";public static final String VIDEO_METRICS_KEY = "video:metrics:";public static final String VIDEO_LIKEUSERS_KEY = "video:likes:";// 视频相关字段public static final String VIDEO_LIKE_NUM = "likeNum";public static final String VIDEO_COLLECT_NUM = "collectNum";public static final String VIDEO_COIN_NUM = "coinNum";// 时间常量public static final long TIME_SECONDS_DAY = 86400; // 一天的秒数
}
6. 优点
  1. 封装性强:所有 Redis 操作封装在 RedisComponentRedisUtils 中,代码更简洁,易于维护。
  2. 通用性:支持任意类型的键和值,适用于多种场景。
  3. 扩展性:可以轻松扩展到其他 Redis 数据结构的操作。
  4. 性能优化:通过定时任务只同步有变动的视频数据,减少数据库压力。

过程具体描述

1. 视频信息的缓存和数据库同步

流程描述

  1. 获取视频信息

    • 用户请求获取视频详细信息。
    • 系统首先从 Redis 缓存中查找视频信息。
    • 如果缓存中存在视频信息,直接返回给用户。
    • 如果缓存中不存在视频信息,系统从数据库中获取视频信息。
    • 将获取到的视频信息保存到 Redis 缓存中,以便后续请求可以直接从缓存中获取。
    • 返回视频信息给用户。
  2. 用户行为处理

    • 用户进行点赞、收藏或投币操作。
    • 系统根据用户操作类型,调用相应的处理方法。
    • 对于点赞操作,系统检查用户是否已经点赞。如果已经点赞,则取消点赞;如果没有点赞,则添加点赞。
    • 对于收藏操作,系统检查用户是否已经收藏。如果已经收藏,则取消收藏;如果没有收藏,则添加收藏。
    • 对于投币操作,系统检查用户是否有足够的硬币。如果有足够的硬币,则进行投币操作;如果没有足够的硬币,则返回错误信息。
    • 更新视频的相应指标(点赞数、收藏数、投币数)。
  3. 定时任务同步缓存到数据库

    • 定时任务每5分钟执行一次。
    • 系统从 Redis 缓存中获取所有视频的指标信息。
    • 对于每个视频,系统更新数据库中的相应指标。
    • 删除旧的缓存信息,确保缓存的及时性和准确性。
2. 流程图

获取视频信息流程图

+----------------+       +----------------+       +----------------+
| 用户请求视频    |  -->  | 从Redis缓存中  |  -->  | 返回视频信息   |
| 详细信息        |       | 查找视频信息  |       | 给用户         |
+----------------+       +----------------+       +----------------+^||  缓存中不存在v+----------------+| 从数据库中      || 获取视频信息    |+----------------+^||  保存到Redisv+----------------+| 将视频信息      || 保存到缓存      |+----------------+

用户行为处理流程图

+----------------+       +----------------+       +----------------+
| 用户进行点赞、  |  -->  | 系统调用相应   |  -->  | 更新视频指标    |
| 收藏或投币操作 |       | 的处理方法      |       | (点赞数、收藏数  |
|                |       |                 |       | 、投币数)        |
+----------------+       +----------------+       +----------------+^||  点赞操作v+----------------+| 检查用户是否    || 已经点赞        |+----------------+^||  已点赞v+----------------+| 取消点赞        |+----------------+^||  未点赞v+----------------+| 添加点赞        |+----------------+

定时任务同步缓存到数据库流程图

+----------------+       +----------------+       +----------------+
| 定时任务每5    |  -->  | 从Redis缓存中  |  -->  | 更新数据库中的  |
| 分钟执行一次    |       | 获取所有视频    |       | 相应指标        |
+----------------+       +----------------+       +----------------+^||  删除旧的v+----------------+| 删除旧的缓存    || 信息            |+----------------+
3. 详细描述

获取视频信息

  1. 用户请求获取视频详细信息。
  2. 系统首先从 Redis 缓存中查找视频信息。
  3. 如果缓存中存在视频信息,直接返回给用户。
  4. 如果缓存中不存在视频信息,系统从数据库中获取视频信息。
  5. 将获取到的视频信息保存到 Redis 缓存中,以便后续请求可以直接从缓存中获取。
  6. 返回视频信息给用户。

用户行为处理

  1. 用户进行点赞、收藏或投币操作。
  2. 系统根据用户操作类型,调用相应的处理方法。
  3. 对于点赞操作,系统检查用户是否已经点赞。如果已经点赞,则取消点赞;如果没有点赞,则添加点赞。
  4. 对于收藏操作,系统检查用户是否已经收藏。如果已经收藏,则取消收藏;如果没有收藏,则添加收藏。
  5. 对于投币操作,系统检查用户是否有足够的硬币。如果有足够的硬币,则进行投币操作;如果没有足够的硬币,则返回错误信息。
  6. 更新视频的相应指标(点赞数、收藏数、投币数)。

定时任务同步缓存到数据库

  1. 定时任务每5分钟执行一次。
  2. 系统从 Redis 缓存中获取所有视频的指标信息。
  3. 对于每个视频,系统更新数据库中的相应指标。
  4. 删除旧的缓存信息,确保缓存的及时性和准确性。

文章转载自:

http://ePep17LP.hhxpL.cn
http://z7lvhCjk.hhxpL.cn
http://qbxNWb9d.hhxpL.cn
http://T9DFYINc.hhxpL.cn
http://rcDMLelY.hhxpL.cn
http://RGP40Thh.hhxpL.cn
http://dxEhW1ly.hhxpL.cn
http://TCO7WbmX.hhxpL.cn
http://s4Q8tDua.hhxpL.cn
http://pqIQObPC.hhxpL.cn
http://jnhrOrIP.hhxpL.cn
http://jQLQAzPQ.hhxpL.cn
http://iQmitOe7.hhxpL.cn
http://f7RmjmPt.hhxpL.cn
http://QrYozn4U.hhxpL.cn
http://HFhel5K5.hhxpL.cn
http://FjJR4c32.hhxpL.cn
http://9q3xiSwU.hhxpL.cn
http://JPARq9bo.hhxpL.cn
http://AndflR4x.hhxpL.cn
http://ziMoHk0A.hhxpL.cn
http://au5y8mq2.hhxpL.cn
http://P2ygmYva.hhxpL.cn
http://iBBFBklN.hhxpL.cn
http://ZUo8UsGC.hhxpL.cn
http://Q1TN7tOo.hhxpL.cn
http://sA7VW8U0.hhxpL.cn
http://I7mNniSp.hhxpL.cn
http://JMxUWz8S.hhxpL.cn
http://tGIIOHLK.hhxpL.cn
http://www.dtcms.com/wzjs/759482.html

相关文章:

  • 网站建设行情建筑工程公司注册需要什么条件
  • 维护网站多少钱两耳清风怎么做网站
  • 网站php源码破解版网站开发需求分析模板
  • 效果好的网站制作上海seo整站优化
  • wordpress站点登陆肇庆网站建设方案外包
  • 织梦的网站地图更新宁波网站设计方案
  • 建筑专业网站有哪些公司装修效果图办公室
  • 网站数据统计直播是网站怎么做
  • 卡盟网站制作宁波建站推广技术公司
  • 网站备案添加域名要建设一个网站需要准备些什么
  • 网站建设要考虑的问题小程序开发费用一览表fhq华网天下
  • 福建建设资格执业注册管理中心网站最新站群
  • 网站建设需要桂ajax吗内蒙古城乡建设网站换名字了
  • 网站制作前需要进行规划设计织梦快速建站
  • 江西省城乡建设培训中心网站汕头seo网站建设
  • 替代wordpress的软件兰州企业网站优化
  • 义乌网站制作云主机建网站教程
  • 做家乡特产的网站用源码搭建网站
  • 网站优化课程培训个人简历制作免费模板
  • 研究院 网站建设seo培训学校
  • 化学试剂购买网站厦门网站开发
  • 想开发自己的网站施工企业研发资金投入情况说明
  • 汉化主题做网站西安网页制作培训机构
  • 做pvc卡片的交流网站sns网站开发
  • 常州网站建设哪家好如何做网站来做淘宝客
  • 广州市网站建设报价建设常规的网站报价是多少钱
  • 适合个人网站的名称手机百度问一问
  • 个人网站用什么开发经销商城建站
  • 文章网站是怎么做的有关网站建设的外文文献
  • 平台网站建设协议国外建筑设计网站