首頁  >  文章  >  資料庫  >  怎麼利用Redis實現讚功能

怎麼利用Redis實現讚功能

WBOY
WBOY轉載
2023-05-27 22:37:042934瀏覽

MySQL 和 Redis優缺點

首先我們來談談兩種方法各自的優缺點:我們以 MySQL 和 Redis 為例。

1、直接寫入資料庫:

優點:此方法實作簡單,只要完成資料庫的增刪改查就行;

缺點:資料庫讀寫壓力大,如果遇到熱門文章在短時間內被大量點讚的情況,直接操作資料庫會給資料庫帶來巨大壓力,影響效率。

2、使用Redis 快取:

優點:效能高,讀寫速度快,緩解資料庫讀寫的壓力;

缺點:開發複雜,無法保證資料安全性即redis 掛掉的時候會遺失數據, 同時不及時同步redis 中的數據, 可能會在redis 記憶體置換的時候被淘汰掉。不過對於點讚數據我們不需要那麼精確,所以丟失一點數據問題不大。

接下來就從以下三個面向對按讚功能做詳細的介紹

#•Redis 快取設計

•資料庫設計

•開啟定時任務持久化儲存到資料庫

1、Redis 快取設計及實作

我們已經在前一篇文章中介紹瞭如何整合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 儲存結構如圖

怎麼利用Redis實現讚功能

怎麼利用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 &#39;被点赞的用户id&#39;,
  `liked_post_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT &#39;点赞的用户id&#39;,
  `status` tinyint(1) NULL DEFAULT 1 COMMENT &#39;点赞状态,0取消,1点赞&#39;,
  `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT &#39;创建时间&#39;,
  `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT &#39;修改时间&#39;,
  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 = &#39;用户点赞表&#39; 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實現讚功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除