怎么利用Redis实现点赞功能
MySQL 和 Redis优缺点
首先我们来说一下两种方法各自的优缺点:我们以 MySQL 和 Redis 为例。
1、直接写入数据库:
优点:这种方法实现简单,只需完成数据库的增删改查就行;
缺点:数据库读写压力大,如果遇到热门文章在短时间内被大量点赞的情况,直接操作数据库会给数据库带来巨大压力,影响效率。
2、使用 Redis 缓存:
优点:性能高,读写速度快,缓解数据库读写的压力;
缺点:开发复杂,不能保证数据安全性即 redis 挂掉的时候会丢失数据, 同时不及时同步 redis 中的数据, 可能会在 redis 内存置换的时候被淘汰掉。不过对于点赞数据我们不需要那么精确,丢失一点数据问题不大。
接下来就从以下三个方面对点赞功能做详细的介绍
&
bull;
Redis 缓存设计
&
bull;
数据库设计
&
bull;
开启定时任务持久化存储到数据库
我们已经在前一篇文章中介绍了如何整合Redis,在这里就不再重复说明了。我们了解到,在进行点赞操作时,需要记录以下几种数据:用户被其他用户点赞的详细记录和点赞操作的记录。为了方便查询和存取,我使用了 Hash 结构进行存储,其存储结构如下:
(1)某用户被其他用户点赞的详细记录: MAP_USER_LIKED 为键值, 被点赞用户id::点赞用户id 为 filed, 1或者0 为 value
(2)某用户被点赞的数量统计: MAP_USER_LIKED_COUNT 为键值, 被点赞用户id 为 filed, count 为 value
部分代码如下/*** 将用户被其他用户点赞的数据存到redis
*/
@Override
public void saveLiked2Redis(String likedUserId, String likedPostId) {
String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED,key, LikedStatusEnum.LIKE.getCode());
}
//取消点赞
@Override
public void unlikeFromRedis(String likedUserId, String likedPostId) {
String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED,key,LikedStatusEnum.UNLIKE.getCode());
}
/**
* 将被点赞用户的数量+1
*/
@Override
public void incrementLikedCount(String likedUserId) {
redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,likedUserId,1);
}
//-1
@Override
public void decrementLikedCount(String likedUserId) {
redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1);
}
/**
* 获取Redis中的用户点赞详情记录
*/
@Override
public List<
UserLikeDetail>
getLikedDataFromRedis() {
Cursor<
Map.Entry<
Object,Object>
>
scan = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
List<
UserLikeDetail>
list = new ArrayList<
>
();
while (scan.hasNext()){
Map.Entry<
Object, Object>
entry = scan.next();
String key = (String) entry.getKey();
String[] split = key.split("
::"
);
String likedUserId = split[0];
String likedPostId = split[1];
Integer value = (Integer) entry.getValue();
//组装成 UserLike 对象
UserLikeDetail userLikeDetail = new UserLikeDetail(likedUserId, likedPostId, value);
list.add(userLikeDetail);
//存到 list 后从 Redis 中删除
redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
}
return list;
}
/**
* 获取Redis中的用户被点赞数量
*/
@Override
public List<
UserLikCountDTO>
getLikedCountFromRedis() {
Cursor<
Map.Entry<
Object,Object>
>
cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
List<
UserLikCountDTO>
list = new ArrayList<
>
();
while(cursor.hasNext()){
Map.Entry<
Object, Object>
map = cursor.next();
String key = (String) map.getKey();
Integer value = (Integer) map.getValue();
UserLikCountDTO userLikCountDTO = new UserLikCountDTO(key,value);
list.add(userLikCountDTO);
//存到 list 后从 Redis 中删除
redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,key);
}
return list;
} Redis 存储结构如图2、数据库设计
这里我们可以和直接将点赞数据存到数据库一样,设计两张表:
(1)用户被其他用户点赞的详细记录:user_like_detail
DROP TABLE IF EXISTS `user_like_detail`;CREATE TABLE `user_like_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`liked_user_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '
被点赞的用户id'
,
`liked_post_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '
点赞的用户id'
,
`status` tinyint(1) NULL DEFAULT 1 COMMENT '
点赞状态,0取消,1点赞'
,
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '
创建时间'
,
`update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '
修改时间'
,
PRIMARY KEY (`id`) USING BTREE,
INDEX `liked_user_id`(`liked_user_id`) USING BTREE,
INDEX `liked_post_id`(`liked_post_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '
用户点赞表'
ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
(2)用户被点赞的数量统计:user_like_count
DROP TABLE IF EXISTS `user_like_count`;CREATE TABLE `user_like_count` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`like_num` int(11) NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
3、开启定时任务持久化存储到数据库
我们使用 Quartz 来实现定时任务,将 Redis 中的数据存储到数据库中,为了演示效果,我们可以设置一分钟或者两分钟存储一遍数据,这个视具体业务而定。在同步数据的过程中,我们首先要将 Redis 中的数据在数据库中进行查重,舍弃重复数据,这样我们的数据才会更加准确。
部分代码如下//同步redis的用户点赞数据到数据库@Override
@Transactional
public void transLikedFromRedis2DB() {
List<
UserLikeDetail>
list = redisService.getLikedDataFromRedis();
list.stream().forEach(item->
{
//查重
UserLikeDetail userLikeDetail = userLikeDetailMapper.selectOne(new LambdaQueryWrapper<
UserLikeDetail>
()
.eq(UserLikeDetail::getLikedUserId, item.getLikedUserId())
.eq(UserLikeDetail::getLikedPostId, item.getLikedPostId()));
if (userLikeDetail == null){
userLikeDetail = new UserLikeDetail();
BeanUtils.copyProperties(item, userLikeDetail);
//没有记录,直接存入
userLikeDetail.setCreateTime(LocalDateTime.now());
userLikeDetailMapper.insert(userLikeDetail);
}else{
//有记录,需要更新
userLikeDetail.setStatus(item.getStatus());
userLikeDetail.setUpdateTime(LocalDateTime.now());
userLikeDetailMapper.updateById(item);
}
});
}
@Override
@Transactional
public void transLikedCountFromRedis2DB() {
List<
UserLikCountDTO>
list = redisService.getLikedCountFromRedis();
list.stream().forEach(item->
{
UserLikeCount user = userLikeCountMapper.selectById(item.getKey());
//点赞数量属于无关紧要的操作,出错无需抛异常
if (user != null){
Integer likeNum = user.getLikeNum() + item.getValue();
user.setLikeNum(likeNum);
//更新点赞数量
userLikeCountMapper.updateById(user);
}
});
}
随着社交媒体的不断发展,多种多样的点赞功能被广泛应用于网络平台中。在网站中添加点赞功能不仅提高了用户和内容互动的愉悦度,还可以增加网站的活跃度。而Redis,这个快速、开源、高性能的内存数据库,却是实现点赞功能的最佳选择。
1. 点赞功能的作用
点赞功能是一种流行的社交媒体功能,可以让用户表达对某个实体的喜爱和认可。在社交媒体之外,点赞功能也被广泛应用在许多其他类型的网站中,如新闻、博客、视频分享等等。
2. Redis的极速操作
Redis是一种内存数据库,数据全部存储在内存中以实现高速读写。Redis键值对存储方式的快速、简便操作,可以让你快速实现点赞功能。例如你可以用Redis中的一个set类型数据结构来代表点赞的用户列表。
3. Redis的持久化存储
尽管Redis保存的所有数据均存储于内存中,但它具备将内存数据转储至磁盘的能力。在Redis内部的共享对象实现持久化存储,适用于点赞功能。你可以定义一个Redis键,用于存储点赞信息,并使用“bgsave”命令实现数据持久化。
4. 在Redis中实现点赞功能
将Redis用于实现点赞功能,需要创建一个键存储点赞信息。你可以用Redis中的incr命令,将对应实体的点赞数加一,用decr命令将点赞数减一。使用smembers命令查找点赞列表,并可以使用sadd和srem命令添加和删除点赞列表中的用户。
5. 为网站添加点赞功能
你只需要在网站中添加一个点赞按钮,然后通过JavaScript将点赞操作发送到Redis数据库,就可以实现点赞功能。可以使用网络套接字框架Socket.IO通过服务器将用户点赞信息发送给Redis。在发生点赞操作时,将点赞的实体和点赞用户存储在Redis中,这种方法可以使得点赞操作更为即时。
6. 优化Redis性能
Redis的性能在很大程度上取决于你如何使用它。使用Redis命令推荐使用Redis站点提供的推荐实践,最大限度地优化性能。你还可以通过部署Redis集群,在多个Redis实例之间分配数据以减少读写负载。
7. 总结
使用Redis实现点赞功能是现代网站互动性的良好实践。Redis提供了快速、可靠和具有高性能的服务器端存储方案。使用Redis,可以始终保持点赞实体数据的准确性和完整性,增强你的网站互动性和用户满意度。