当前位置:网站首页>Redis高效点赞与取消功能
Redis高效点赞与取消功能
2022-07-01 02:57:00 【靈熙雲】
到此 灵熙云工作室 - 实践出真理 查看全文内容

像CSDN的点赞功能只记录了数量,微信朋友圈的点赞功能有显示点赞人头像(获取userId查询用户信息封装返回即可)
点赞、取消点赞是高频次的操作,若每次都读写数据库,大量的操作会影响数据库性能,甚至宕机,所以用缓存处理再合适不过。本文以文章点赞为例来展开叙述
数据格式选择
Redis有5种数据结构分别为:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
由于需要记录文章和点赞人,还有点赞状态(点赞、取消),分析下 Redis 数据格式中Hash最合适。
因为Hash里的数据都是存在一个Key中,通过Key很方便的把所有的点赞数据都取出。Key里面的数据还可以存成键值对的形式,方便存入点赞人、被点赞人和点赞状态。
文章 id为articleId,点赞人的 id为userId,点赞状态为1(点赞)和0(取消点赞)。文章 id和点赞人 id作为HashKey,两个 id 中间用::隔开,点赞状态作为HashValue。

整合SpringBoot
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
基础配置
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
配置类
package cn.goitman.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
/** * @author Nicky * @version 1.0 * @className RedisConfig * @blog goitman.cn | blog.csdn.net/minkeyto * @description Redis配置类 * @date 2022/5/16 14:40 */
@Configuration
public class RedisConfig {
/** * 凡事使用到template的redis操作都必须走@Transanctional注解式事务,要不然会导致连接一直占用,不关闭 */
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate template = new RedisTemplate();
// 改变redisTemplate的序列化方式,key为字符串格式,value为json格式
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// HashKey 和 HashValue 为json格式
template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
// 开启事务支持
template.setEnableTransactionSupport(true);
return template;
}
/** * 配置事务管理器 */
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) throws SQLException {
return new DataSourceTransactionManager(dataSource);
}
}
如果redisTemplate没有序列化,在可视化工具中看到的数据为乱码,获取数据时也可能为空,模糊查询(下文有叙述)功能也使用不了

Redis接口
package cn.goitman.service.impl;
import cn.goitman.pojo.Article;
import cn.goitman.pojo.Likes;
import cn.goitman.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** * @author Nicky * @version 1.0 * @className RedisServiceImpl * @blog goitman.cn | blog.csdn.net/minkeyto * @description Redis接口实现类 * @date 2022/5/13 16:43 */
@Service
@Transactional
public class RedisServiceImpl implements RedisService {
// 文章点赞 KEY
public static final String KEY_ARTICLE_LIKE = "ARTICLE_LIKE";
// 文章点赞数量 KEY
public static final String KEY_ARTICLE_LIKE_COUNT = "ARTICLE_LIKE_COUNT";
@Autowired
RedisTemplate redisTemplate;
/** * 保存点赞和文章点赞量 */
@Override
public void saveLike(String articleId, String userId) {
String field = getLikeKey(articleId, userId);
redisTemplate.opsForHash().put(KEY_ARTICLE_LIKE, field, 1);
redisTemplate.opsForHash().increment(KEY_ARTICLE_LIKE_COUNT, articleId, 1);
}
/** * 取消点赞和文章点赞量 */
@Override
public void unLike(String articleId, String userId) {
String field = getLikeKey(articleId, userId);
redisTemplate.opsForHash().put(KEY_ARTICLE_LIKE, field, 0);
redisTemplate.opsForHash().increment(KEY_ARTICLE_LIKE_COUNT, articleId, -1);
}
/** * 删除点赞数据 */
@Override
public void deleteLike(List<Likes> list) {
for (Likes like : list) {
String field = getLikeKey(like.getArticleId(), like.getUserId());
redisTemplate.opsForHash().delete(KEY_ARTICLE_LIKE, field);
}
}
/** * 删除文章点赞量数据 */
@Override
public void deleteLikeCount(String articleId) {
redisTemplate.opsForHash().delete(KEY_ARTICLE_LIKE_COUNT, articleId);
}
/** * 获取全部点赞数据 */
@Override
public List<Likes> getAllLikeData() {
List<Likes> list = new ArrayList<>();
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(KEY_ARTICLE_LIKE, ScanOptions.NONE);
while (cursor.hasNext()) {
Map.Entry<Object, Object> entry = cursor.next();
String keys = entry.getKey().toString();
String[] keyArr = keys.split("::");
Likes like = new Likes(keyArr[0], keyArr[1], (Integer) entry.getValue());
list.add(like);
}
return list;
}
/** * 获取文章点赞量数据 */
@Override
public List<Article> getArticleLikeCount() {
List<Article> list = new ArrayList<>();
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(KEY_ARTICLE_LIKE_COUNT, ScanOptions.NONE);
while (cursor.hasNext()) {
Map.Entry<Object, Object> entry = cursor.next();
String articleId = entry.getKey().toString();
Article article = new Article(articleId, (Integer) entry.getValue());
list.add(article);
}
return list;
}
/** * 拼接文章ID和点赞人ID作为key */
private String getLikeKey(String articleId, String userId) {
return new StringBuilder().append(articleId).append("::").append(userId).toString();
}
}
搞掂,就是这么简单高效,在Redis内,存在相同数据只会修改value,并且Redis默认RDB持久化数据。
当然也可加上限时内限制每个用户点赞次数的逻辑,防止恶意刷接口,逻辑简单,在此就不累述啦
到此 灵熙云工作室 - 实践出真理 查看全文内容
边栏推荐
- mybati sql 语句打印
- [linear DP] longest common subsequence
- Visual effects, picture to cartoon function
- Analysis and solution of anr problems
- Huawei operator level router configuration example | BGP VPLS and LDP VPLS interworking example
- xxl-job使用指南
- Xception learning notes
- [linear DP] shortest editing distance
- [applet project development -- Jingdong Mall] user defined search component of uni app (Part 1)
- MCU firmware packaging Script Software
猜你喜欢

Detailed explanation of pointer array and array pointer (comprehensive knowledge points)

RestCloud ETL实践之无标识位实现增量数据同步
![[exsi] transfer files between hosts](/img/c3/128b72aca6e030b2d4be2b6bddbc43.png)
[exsi] transfer files between hosts

PHP batch Excel to word

Huawei operator level router configuration example | BGP VPLS and LDP VPLS interworking example

Optimal Transport系列1

Visual effects, picture to cartoon function

Huawei operator level router configuration example | configuration static VPLS example
![[linear DP] longest common subsequence](/img/47/c3172422e997009facbada929adb1a.jpg)
[linear DP] longest common subsequence

基于Pytorch完整的训练一个神经网络并进行验证
随机推荐
Complete training and verification of a neural network based on pytorch
股票开账户如何优惠开户?还有,在线开户安全么?
Const and the secret of pointers
[applet project development -- Jingdong Mall] user defined search component of uni app (Part 1)
Is it safe to open an account online in a small securities firm? Will my money be unsafe?
在国内如何买港股的股?用什么平台安全一些?
鼠标悬停效果三
Add / delete / modify query summary insert/create/put/add/save/post, delete/drop/remove, update/modify/change, select/get/list/find
A shooting training method based on the digital measurement of Joule energy and posture of sphygmomanometer air bag with standard air pressure
Restcloud ETL WebService data synchronization to local
[applet project development -- JD mall] uni app commodity classification page (first)
Pychart software deployment gray unable to point
Huawei operator level router configuration example | BGP VPLS and LDP VPLS interworking example
Youmeng (a good helper for real-time monitoring of software exceptions: crash) access tutorial (the easiest tutorial for Xiaobai with some foundation)
性能测试常见面试题
LeetCode_栈_困难_227.基本计算器(不含乘除)
Densenet network paper learning notes
Mouse over effect II
mybati sql 语句打印
Communication protocol -- Classification and characteristics Introduction