まず、2 つの方法の長所と短所について説明します。MySQL と Redis を例に挙げてみましょう。
1. データベースに直接書き込む:
利点: この方法は実装が簡単で、データベースの追加、削除、変更、クエリを完了するだけで済みます。
短所: データベースは読み取りと書き込みに大きなプレッシャーを受けます。人気のある記事が短期間に多数の「いいね!」を受け取った場合、データベースを直接操作するとデータベースに大きなプレッシャーがかかり、効率に影響します。
2. Redis キャッシュを使用する:
利点: 高いパフォーマンス、高速な読み取りおよび書き込み速度、データベースの読み取りおよび書き込みの負荷を軽減します;
欠点: 複雑な開発、データセキュリティは保証できません 問題は、redis がハングするとデータが失われることですが、同時に、redis 内のデータが同期されていない場合、redis のメモリを交換するとデータが失われる可能性があります。ただし、同様のデータについてはそれほど正確である必要はなく、多少のデータが失われることは大きな問題ではありません。
次に、同様の機能を次の 3 つの側面から詳しく紹介します。
•Redis キャッシュ設計
•データベース設計
•スケジュールされたタスクのデータベースへの永続ストレージを有効にする
Redis を統合する方法を前の記事で紹介しましたが、ここでは再度説明を繰り返すことはありません。いいね操作を行う際には、ユーザーが他のユーザーにいいねされた詳細な記録や、いいね操作の記録を記録する必要があることを理解しています。クエリとアクセスを容易にするために、ストレージにハッシュ構造を使用しました。ストレージ構造は次のとおりです:
(1) ユーザーが他のユーザーにいいねされた詳細な記録: MAP_USER_LIKED
はキー値です。いいねされたユーザー ID:: いいねされたユーザー ID がファイルされます。値は 1 または 0 です。
(2) ユーザーのいいね数の統計: MAP_USER_LIKED_COUNT
がキーです。 value であり、ユーザー ID がファイルされるのと同様に、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; }
ここでは、同様のデータをデータベースに直接保存するのと同じように 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. スケジュールされたタスクの永続ストレージを有効にするデータベースへ
コードの一部は次のとおりです
//同步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 中国語 Web サイトの他の関連記事を参照してください。