利用redis set 实现点赞案例 zset 对点赞进行排序

基于数据库
CREATE TABLE IF NOT EXISTS `liked_record` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',`user_id` bigint NOT NULL COMMENT '用户id',`biz_id` bigint NOT NULL COMMENT '点赞的业务id',`biz_type` VARCHAR(16) NOT NULL COMMENT '点赞的业务类型',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `idx_biz_user` (`biz_id`,`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='点赞记录表';

controller
package com.orchids.likepointbyset.web.controller;import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.result.Result;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
import com.orchids.likepointbyset.web.service.ILikedRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @ Author qwh* @ Date 2024/7/5 19:14*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/likes")
@Api(tags = "基于数据库的点赞点赞业务相关接口")
public class LikedRecordController {private final ILikedRecordService likedRecordService;@PostMapping("points")@ApiOperation("点赞或取消点赞")public Result<LikedRecordVo> addLIkeRecord(@Validated @RequestBody LikeRecordFormDTO recordDTO){LikedRecordVo record = likedRecordService.addLIkeRecord(recordDTO);return Result.ok(record);}
}
package com.orchids.likepointbyset.web.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.result.Result;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;/*** <p>* 点赞记录表 服务类* </p>** @author nullpointer* @since 2024-07-05*/
public interface ILikedRecordService extends IService<LikedRecord> {LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO);
}
service
package com.orchids.likepointbyset.web.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
import com.orchids.likepointbyset.web.exception.SignException;
import com.orchids.likepointbyset.web.mapper.LikedRecordMapper;
import com.orchids.likepointbyset.web.service.ILikedRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;/*** <p>* 点赞记录表 服务实现类* </p>** @author nullpointer* @since 2024-07-05*/
@Service
public class LikedRecordServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {@Overridepublic LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO) {//判断是否是点赞//是点赞在点赞记录表添加点赞记录 取消点赞就把点赞记录删除//true                 //trueboolean success = recordDTO.getLiked()?like(recordDTO):unlike(recordDTO);if (!success){throw new SignException("亲!业务失败了 >︿< 马上好",500);}//保存成功或者取消成功//重新计算总点赞次数Long likePoints = lambdaQuery().eq(LikedRecord::getBizId, recordDTO.getBizId()).count();LikedRecordVo result = new LikedRecordVo();result.setBizId(recordDTO.getBizId());result.setLikeCount(likePoints.intValue());return result;}private boolean like(LikeRecordFormDTO recordDTO) {//假设用户Id为Long userId = 138888L;//查询是否有点赞记录如果有直接退出没有就添加点赞记录Long count = lambdaQuery().eq(LikedRecord::getUserId, userId).eq(LikedRecord::getBizId, recordDTO.getBizId()).count();if (count>0){return false;}//添加记录LikedRecord record = new LikedRecord();record.setUserId(userId);record.setBizId(recordDTO.getBizId());record.setBizType(recordDTO.getBizType());boolean save = save(record);return save;}private boolean unlike(LikeRecordFormDTO recordDTO) {//假设用户Id为Long userId = 138888L;//删除点记录LambdaQueryWrapper<LikedRecord> wrapper = new LambdaQueryWrapper<>();wrapper.eq(LikedRecord::getUserId,userId).eq(LikedRecord::getBizId,recordDTO.getBizId());boolean remove = remove(wrapper);return remove;}
}
测试结果

屏幕截图 2024-07-05 204016.png
屏幕截图 2024-07-05 204039.png
屏幕截图 2024-07-05 204046.png
屏幕截图 2024-07-05 204056.png
屏幕截图 2024-07-05 204103.png

基于redis set
使用redis set 先缓存点赞数据然后使用定时任务批量保存点赞数据 key 为业务id value 为点赞用户的id

使用set中的 size方法统计一条评论的点赞总数
使用zset对每一条评论的点赞数进行排序
配合定时任务定时更新评论区点赞数
image.pngcontroller

package com.orchids.likepointbyset.web.controller;import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.result.Result;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
import com.orchids.likepointbyset.web.service.ILikedRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @ Author qwh* @ Date 2024/7/5 19:14*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/likes")
@Api(tags = "基于数据库的点赞点赞业务相关接口")
public class LikedRecordController {private final ILikedRecordService likedRecordService;@PostMapping("points")@ApiOperation("点赞或取消点赞")public Result<LikedRecordVo> addLIkeRecord(@Validated @RequestBody LikeRecordFormDTO recordDTO){LikedRecordVo record = likedRecordService.addLIkeRecord(recordDTO);return Result.ok(record);}
}
service
package com.orchids.likepointbyset.web.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.result.Result;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;/*** <p>* 点赞记录表 服务类* </p>** @author nullpointer* @since 2024-07-05*/
public interface ILikedRecordService extends IService<LikedRecord> {LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO);/*** 用于发送消息将redis中的数据取出并统计* @param bizType* @param maxBizSize*/void readLikedTimesAndSendMessage(String bizType, int maxBizSize);
}
package com.orchids.likepointbyset.web.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO;
import com.orchids.likepointbyset.web.domain.dto.LikedTimesDTO;
import com.orchids.likepointbyset.web.domain.po.LikedRecord;
import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
import com.orchids.likepointbyset.web.exception.SignException;
import com.orchids.likepointbyset.web.mapper.LikedRecordMapper;
import com.orchids.likepointbyset.web.service.ILikedRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;import java.util.ArrayList;
import java.util.Set;/*** @ Author qwh* @ Date 2024/7/5 21:07*/
@Slf4j
@Service
@RequiredArgsConstructor
public class LikedRecordRedisServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {private final StringRedisTemplate redisTemplate;private final String LIKE_SET_BIZ = "like:set:biz";private final String LIKE_SET_BIZ_SUM = "like:set:biz:type";private final String LIKE_RECORD_EXCHANGE = "like.record.topic";private final String LIKED_TIMES_KEY_TEMPLATE = "qa.times.changed";private final RabbitTemplate rabbitTemplate;/*** 对一条评论的点赞一个视频的点赞 一个评论有许多条评论 一个页面哟许多视频 在评论区可以根据 点赞数量进行排序 就是是高赞评论 或者高质量视频* @param recordDTO* @return*/@Overridepublic LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO) {// 1.基于前端的参数,判断是执行点赞还是取消点赞boolean success = recordDTO.getLiked() ? like(recordDTO) : unlike(recordDTO);if (!success){throw new SignException("亲!业务失败了 >︿< 马上好",500);}//计算点赞总数Long likeCount = redisTemplate.opsForSet().size(LIKE_SET_BIZ + recordDTO.getBizId());if (likeCount == null){throw new SignException("亲 该评论还未被点赞过急需 您的点赞(✿◡‿◡)",203);}//将该评论总数缓存总数到redis  //todo 后序可以对该评论区的热评进行排序Boolean add = redisTemplate.opsForZSet().add(LIKE_SET_BIZ_SUM +":"+ recordDTO.getBizType(), recordDTO.getBizId().toString(), likeCount);//返回点赞数LikedRecordVo result = new LikedRecordVo();result.setBizId(recordDTO.getBizId());result.setLikeCount(likeCount.intValue());return result;}@Overridepublic void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {//读取redis中的该评论的点赞总数String key = LIKE_SET_BIZ_SUM + bizType;//从redis中取出30条评论 点赞数由小到大Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().popMin(key, maxBizSize);if (CollectionUtils.isEmpty(tuples)){return;}//数据转换ArrayList<LikedTimesDTO> list = new ArrayList<>(tuples.size());for (ZSetOperations.TypedTuple<String> tuple : tuples) {LikedTimesDTO dto = new LikedTimesDTO();String bizId = tuple.getValue();Double likeCount = tuple.getScore();if (bizId==null||likeCount==null){continue;}dto.setBizId(Long.valueOf(bizId));dto.setLikedCounts(likeCount.intValue());list.add(dto);}log.error("评论区点赞数据{}",list);if (!CollectionUtils.isEmpty(list)) {//发送MQ消息  将评论区中的点赞数据保存到数据库rabbitTemplate.convertAndSend(LIKE_RECORD_EXCHANGE, LIKED_TIMES_KEY_TEMPLATE, list);//由评论区业务监听这个消息 监听后更新评论区数据//todo 由评论区消费者消费这些消息}};private boolean like(LikeRecordFormDTO recordDTO) {//假设用户Id为Long userId = 138888L;//获取keyString key = LIKE_SET_BIZ + recordDTO.getBizId();Long result = redisTemplate.opsForSet().add(key, userId.toString());//点赞成功return result !=null && result > 0;}private boolean unlike(LikeRecordFormDTO recordDTO) {//假设用户Id为Long userId = 138888L;//获取keyString key = LIKE_SET_BIZ + recordDTO.getBizId();Long result = redisTemplate.opsForSet().remove(key, userId.toString());//点赞成功return result !=null && result > 0;}}
其他类
  1. 定时任务
package com.orchids.likepointbyset.web.task;import com.orchids.likepointbyset.web.service.ILikedRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;/*** @ Author qwh* @ Date 2024/7/5 21:50*/
@Component
@RequiredArgsConstructor
public class TimesCheckLikedTask {private final ILikedRecordService recordService;//这个理解为视频唯一IDprivate static final List<String> BIZ_TYPES = Arrays.asList("QA","NOTE");private static final int MAX_BIZ_SIZE = 30;//每20秒保存批量保存一次数据到数据库@Scheduled(cron = "5 * * * * *")public void TimesCheckLiked(){for (String bizType : BIZ_TYPES) {recordService.readLikedTimesAndSendMessage(bizType, MAX_BIZ_SIZE);}}
}
  1. 启动类
package com.orchids.likepointbyset;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;@EnableScheduling
@SpringBootApplication
@ComponentScan(basePackages = "com.orchids.likepointbyset.web")
public class LikepointbyzsetApplication {public static void main(String[] args) {SpringApplication.run(LikepointbyzsetApplication.class, args);}}
测试因为要写其他业务就算了 思想理解了 就行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/41490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外金融机构银行保险证券数字化转型营销销售数字化成功案例讲师培训师讲授开户销售营销客户AI人工智能创新思维

金融机构需要数字营销的主要原因 数字银行、直接存款和移动网络的兴起让客户无需前往当地分行即可轻松办理银行业务。这些举措不仅提升了用户体验&#xff0c;也迫使银行向数字化世界迈进。 金融服务公司需要在数字营销渠道上保持稳固的地位&#xff0c;以免落后于大型机构。…

Stream的获取、中间方法、终结方法

1、获取Stream流 单列集合&#xff1a;foreach完整版 双列集合通过Ketset()、entryset() 数组的&#xff1a;通过Arrays Stream流的中间方法&#xff1a;链式编程&#xff0c;原stream流只能使用一次 filter&#xff1a; limit、skip&#xff1a; distinct(有自定义对象需要重写…

群体优化算法---猫群算法介绍,物流配送路径规划(包含3-opt,贪心算法)

介绍 猫群算法&#xff08;Cat Swarm Optimization&#xff0c;CSO&#xff09;是一种新型的基于群体智能的优化算法&#xff0c;由Chu et al.在2006年提出。该算法通过模拟猫的行为&#xff0c;尤其是其两种主要的行为&#xff1a;追捕行为&#xff08;seeking mode&#xff…

LangChain(三)基础问答大模型,从LLMchain开始了解chain!纯新手向

背景 经过前面两篇内容的部分&#xff0c;我想大家应该对Langchain有了一个初步的了解。那么我们接下来完善我们的基础大模型吧&#xff01;开始chain的尝试&#xff01; Chain的说明 chain可谓是Langchain的精髓所在&#xff0c;不使用chain&#xff0c;也就没必要学习Lang…

AWS云服务器的竞争优势

亚马逊网络服务&#xff08;AWS&#xff09;作为全球最大的云计算平台&#xff0c;在激烈的市场竞争中一直保持领先地位。相较于其他云服务提供商&#xff0c;AWS云服务器具有多方面的显著优势&#xff0c;使其成为众多企业和开发者的首选&#xff0c;我们结合九河云的分析一起…

机器学习 - one-hot编码技术

One-hot编码是一种数据处理技术&#xff0c;主要用于将分类变量转换为适合机器学习算法处理的格式。在One-hot编码中&#xff0c;每个类别值都会被转换成一个二进制向量&#xff0c;其中只有一个元素是1&#xff0c;其余所有元素都是0。这种编码方式确保了类别之间的独立性和唯…

如何在前端网页实现live2d的动态效果

React如何在前端网页实现live2d的动态效果 业务需求&#xff1a; 因为公司需要做机器人相关的业务&#xff0c;主要是聊天形式的内容&#xff0c;所以需要一个虚拟的卡通形象。而且为了更直观的展示用户和机器人对话的状态&#xff0c;该live2d动画的嘴型需要根据播放的内容来…

WEBHTTP

目录 理解HTTP协议请求流程 1 1 Web基础 2 Hosts文件 1 1 2网页与HTML 2 HTML概述 1 1 3静态网页与动态网页 1.2HTTP协议 1 2 1 HTTP协议概述 1 2 2 HTTP方法 HTTP支持几种不同的请求命令&#xff0c;这些命令被称为HTTP方法(HTTP method 表1一3 HTTP方法 表1&#…

开源协作wiki和文档软件Docmost

什么是 Docmost &#xff1f; Docmost 是一款开源协作 wiki 和文档软件。它是 Confluence 和 Notion 等软件的开源替代品。使用 Docmost 可以无缝创建、协作和共享知识。非常适合管理您的 wiki、知识库、文档等。目前 Docmost 处于测试阶段。 软件的主要特点 安装 在群晖上以 …

Python面试题:请解释 Python 的垃圾回收机制

Python 的垃圾回收机制主要通过引用计数&#xff08;Reference Counting&#xff09;和循环垃圾收集&#xff08;Cycle Garbage Collection&#xff09;来管理内存。以下是对这两种机制及其相关知识点的详细解析&#xff1a; 引用计数 原理 每个对象都有一个引用计数器&…

Linux运维:MySQL备份,物理冷备份,热备,完备+二进制日志

备份类型 完全备份、增量备份、差异备份 完全备份&#xff1a;整个数据集都备份 增量备份&#xff1a;仅备份最近一次完全备份或增量备份&#xff08;如果存在增量&#xff09;以来变化的数据&#xff0c;备份较快&#xff0c;还原复杂。 差异备份&#xff1a;对比前一次备…

Renesas R7FA8D1BH (Cortex®-M85) ADC模块应用

目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP和KEIL配置ADC 2.1 ADC硬件接口 2.2 FSP配置ADC 3 软件功能实现 3.1 FSP生成项目 3.2 FSP ADC模块库函数介绍 3.2.1 库函数列表 3.2.2 函数介绍 4 ADC功能代码 4.1 编写代码 4.2 代码…

计算机应用数学--第三次作业

第三次作业计算题编程题1 基于降维的机器学习2 深度学习训练方法总结 第三次作业 计算题 (15 分&#xff09;对于给定矩阵 A A A&#xff08;规模为 42&#xff09;&#xff0c;求 A A A 的 SVD&#xff08;奇异值分解&#xff09;&#xff0c;即求 U U U&#xff0c; Σ …

Ardupilot无人船(车)mavros自主控制

文章目录 前言一、启动仿真二、编写代码三、运行前言 ubuntu20.04 rover 4.4 学习资料: https://cwkj-tech.yuque.com/bsge84/suv1 https://ardupilot.org/dev/docs/mavlink-rover-commands.html http://wiki.ros.org/mavros 一、启动仿真 在ardupilot/Rover目录下执行: …

强化学习-6 DDPG、PPO、SAC算法

文章目录 1 DPG方法2 DDPG算法3 DDPG算法的优缺点4 TD3算法4.1 双Q网络4.2 延迟更新4.3 噪声正则 5 附15.1 Ornstein-Uhlenbeck (OU) 噪声5.1.1 定义5.1.2 特性5.1.3 直观理解5.1.4 数学性质5.1.5 代码示例5.1.6 总结 6 重要性采样7 PPO算法8 附28.1 重要性采样方差计算8.1.1 公…

重塑通信边界,基于ZYNQ7000 FPGA驱动的多频段多协议软件无线电平台

01、产品概述 本平台是基于高性能ZYNQ-7000系列中的XC7Z045处理器构建的多频段多协议软件无线电解决方案&#xff0c;集成了AD9364芯片——一款业界领先的1x1通道RF敏捷收发器&#xff0c;为无线通信应用提供了强大支持。其存储架构包括2路高速4GB DDR3内存、1路32GB EMMC存储以…

一道有意思的简单题 [NOIP2010 普及组] 接水问题

题目&#xff1a; 题解&#xff1a; 每一次新来的同学的接水时间都加在现在已有的水龙头中接水时间最短的&#xff0c;总时间就为n次操作后水龙头中接水时间的最长值。 #include<bits/stdc.h> using namespace std; multiset<int>s;int main(){int n,m;scanf(&qu…

uni-app组件 子组件onLoad、onReady事件无效

文章目录 导文解决方法 导文 突然发现在项目中&#xff0c;组件 子组件的onLoad、onReady事件无效 打印也出不来值 怎么处理呢&#xff1f; 解决方法 mounted() {console.log(onLoad, this.dateList);//有效// this.checkinDetails()},onReady() {console.log(onReady, this.da…

空间数据采集与管理:为什么选择ArcGISPro和Python?

你还在为找不到合适的数据而苦恼吗&#xff1f;你还在面对大量数据束手无策&#xff0c;不知如何处理吗&#xff1f;对于从事生产和科研的人员来说&#xff0c;空间数据的采集与管理是地理信息系统&#xff08;GIS&#xff09;和空间分析领域的关键环节。通过准确高效地采集和管…

贪心算法-以高校教师信息管理系统为例

1.贪心算法介绍 1.算法思路 贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行&#xff0c;根据某个优化测度&#xff0c;每一 步都要确保能获得局部最优解。每一步只考虑一 个数据&#xff0c;其选取应该满足局部优化的条件。若下 一个数据和部分最优解连在一起不…