>데이터 베이스 >Redis >Redis를 사용하여 like 기능을 구현하는 방법

Redis를 사용하여 like 기능을 구현하는 방법

WBOY
WBOY앞으로
2023-05-27 22:37:042979검색

MySQL과 Redis의 장단점

먼저 두 가지 방법의 장단점에 대해 이야기해 보겠습니다. MySQL과 Redis를 예로 들어 보겠습니다.

1. 데이터베이스에 직접 쓰기:

장점: 이 방법은 구현이 간단하며 데이터베이스의 추가, 삭제, 수정 및 쿼리만 완료하면 됩니다.

단점: 데이터베이스를 읽어야 하는 부담이 큽니다. 짧은 시간에 많이 읽히는 인기글을 접하게 된다면, 좋아요의 경우 데이터베이스를 직접 운영하게 되면 데이터베이스에 큰 부담을 주고 효율성에 영향을 미칠 것입니다.

2. Redis 캐시 사용:

장점: 고성능, 빠른 읽기 및 쓰기 속도, 데이터베이스 읽기 및 쓰기 부담 완화

단점: 복잡한 개발, 데이터 보안을 보장할 수 없습니다. 즉, 데이터가 손실됩니다. 동시에 Redis의 데이터가 시간에 맞춰 동기화되지 않으면 Redis 메모리 교체 중에 제거될 수 있습니다. 그러나 유사한 데이터에 대해서는 너무 정확할 필요가 없으며 약간의 데이터가 손실되는 것은 큰 문제가 아닙니다.

다음은 다음 세 가지 측면에서 like 기능에 대한 자세한 소개입니다

•Redis 캐시 디자인

•데이터베이스 디자인

•예약된 작업을 데이터베이스에 영구 저장 가능

1. 캐시 설계 및 구현

이전 글에서 Redis를 통합하는 방법을 이미 소개했으므로 여기서는 반복하지 않겠습니다. 유사한 작업을 수행할 때 다른 사용자가 좋아하는 사용자에 대한 자세한 기록 및 유사한 작업에 대한 기록과 같은 데이터가 기록되어야 함을 이해합니다. 쿼리 및 접근을 용이하게 하기 위해 저장 구조는 다음과 같습니다.

(1) 다른 사용자가 좋아한 사용자의 세부 기록: MAP_USER_LIKED가 핵심입니다. value, like like user id:: user id가 등록된 것처럼 1 또는 0이 valueMAP_USER_LIKED 为键值, 被点赞用户id::点赞用户id 为 filed, 1或者0 为 value

(2)某用户被点赞的数量统计: MAP_USER_LIKED_COUNT 为键值, 被点赞用户id 为 filed, count

(2) 사용자의 좋아요 수 통계: MAP_USER_LIKED_COUNT가 키 값이고, 사용자 ID가 등록된 것처럼 count는 값입니다

코드의 일부는 다음과 같습니다

/**
* 将用户被其他用户点赞的数据存到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를 사용하여 like 기능을 구현하는 방법

Redis를 사용하여 like 기능을 구현하는 방법

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의 데이터를 데이터베이스에 저장하여 효과를 입증하기 위해 데이터가 1분 또는 2분에 한 번 저장되도록 설정할 수 있습니다. , 특정 비즈니스에 따라 다릅니다. 데이터를 동기화하는 과정에서 먼저 데이터베이스에 있는 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를 사용하여 like 기능을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제