redis初体验

第一次在项目中使用redis,我写的点赞功能因为使用频率高,所以我选择使用了redis。这是我痛苦的开始,我以为点赞功能很好写的结果这么麻烦,因为存到redis里的key值的问题,我想了很久,最终解决了。但是我发现帖子的点赞,帖子的收藏,专辑的点赞,专辑的收藏,这些都差不多。后面写的也快了很多。
使用redis遇到了一些问题。
因为刚开始没有给redis加密码,而且在root用户上运行,导致攻击端口的行为出现,然后我的6379端口被封禁了一天。于是我改了个端口号,在另一个用户上运行。但是…,因为没给另一个用户足够的权限,总是频频报错。最终还是解决了。
把这次解决思路redis点赞的代码展示一下。

首先需要一个RedisKeyUtils,得到存在redis里的key值

public class RedisKeyUtils {

    //保存用户点赞数据的key
    public static final String MAP_KEY_USER_LIKED = "MAP_USER_LIKED";
    //保存用户被点赞数量的key
    public static final String MAP_KEY_USER_LIKED_COUNT = "MAP_USER_LIKED_COUNT";
    //保存热门推荐帖子
    /**
     * 拼接被点赞的帖子id和点赞的人的id作为key。格式 222222::333333
     * @param likedUserId 点赞的人id
     * @param likedPostId 点赞的帖子的id
     * @return
     */
    public static String getLikedKey(String likedUserId, String likedPostId){
        StringBuilder builder = new StringBuilder();
        builder.append(likedPostId);
        builder.append("::");
        builder.append(likedUserId);

        return builder.toString();
    }
   

用户点赞的实体类UserLike :

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserLike {
    /**
     * id
     */
    private int id;

    /**
     * 点赞人的id
     */
    private Integer userId;

    /**
     * 点赞帖子的id
     */
    private Integer postId;
    /**
     * 时间
     */
    private String time;

    /**
     * 点赞状态
     */
    private Integer status;

    public UserLike(Integer userId,Integer postId,Integer status){
        this.userId = userId;
        this.status = status;
        this.postId = postId;
    }
}

点赞数量实体类LikedCountDTO :

package future.image.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class LikedCountDTO {

    /**
     * 帖子id
     */
    private String id;

    /**
     * 点赞收藏数量
     */
    private int count;
}

一个redis的service,里面定义点赞需要的方法。


import future.image.pojo.*;
import future.image.utils.Result;

import java.util.List;

/**
 * @author zrl
 */
public interface RedisService {

    /**
     * 点赞。状态为1
     * @param likedUserId
     * @param likedPostId
     */
    void saveLiked2Redis(String likedUserId, String likedPostId);


    /**
     * 取消点赞。将状态改变为0
     * @param likedUserId
     * @param likedPostId
     */
    void unlikeFromRedis(String likedUserId, String likedPostId);

    /**
     * 从Redis中删除一条点赞数据
     * @param likedUserId
     * @param likedPostId
     */
    void deleteLikedFromRedis(String likedUserId, String likedPostId);

    /**
     * 该用户的点赞数加1
     * @param likedPostId
     */
    void incrementLikedCount(String likedPostId);

    /**
     * 该用户的点赞数减1
     * @param likedPostId
     */
    void decrementLikedCount(String likedPostId);

    /**
     * 获取Redis中存储的所有点赞数据
     * @return
     */
    List<UserLike> getLikedDataFromRedis();

    /**
     * 获取Redis中存储的所有点赞数量
     * @return
     */
    List<LikedCountDTO> getLikedCountFromRedis();


    /**
     * 点赞数量
     */
    Result getThumbUpCount(Integer postId);
}

以及它的是实现类RedisServiceImpl


import future.image.dao.CollectMapper;
import future.image.dao.ForumMapper;
import future.image.pojo.*;
import future.image.service.LikedService;
import future.image.service.RedisService;
import future.image.utils.RedisKeyUtils;
import future.image.utils.RedisUtil;
import future.image.utils.Result;
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 javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author zrl
 */
@Service("redisService")
public class RedisServiceImpl implements RedisService {

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    LikedService likedService;

    @Resource
    ForumMapper forumMapper;

    @Resource
    RedisUtil redisUtil;

    @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());
    }


    @Override
    public void deleteLikedFromRedis(String likedUserId, String likedPostId) {
        String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
        redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
    }

    @Override
    public void incrementLikedCount(String likedPostId) {
        boolean flag = redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,likedPostId);
        if(flag){
            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedPostId, 1);
        }else{
            int count = forumMapper.getThumbUpCount(Integer.parseInt(likedPostId));
            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedPostId, count+1);
        }
    }




    @Override
    public void decrementLikedCount(String likedPostId) {
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedPostId, -1);
    }

    @Override
    public void decrementCollectForumCount(String postId) {
        boolean flag = redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_COLLECT_FORUM_COUNT,postId);
        if(flag){
            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_COLLECT_FORUM_COUNT, postId, -1);
        }else{
            int count = collectMapper.getCollectForumCount(Integer.parseInt(postId));
            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_COLLECT_FORUM_COUNT, postId, count-1);

        }

    }

    @Override
    public List<UserLike> getLikedDataFromRedis() {
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        List<UserLike> list = new ArrayList<>();
        while (cursor.hasNext()){
            Map.Entry<Object, Object> entry = cursor.next();
            String key = (String) entry.getKey();
            //分离出 likedUserId,likedPostId
            String[] split = key.split("::");
            String likedPostId = split[0];
            String likedUserId = split[1];
            Integer value = (Integer) entry.getValue();

            //组装成 UserLike 对象
            UserLike userLike = new UserLike(Integer.parseInt(likedUserId), Integer.parseInt(likedPostId), value);
            list.add(userLike);

            //存到 list 后从 Redis 中删除
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
        }

        return list;
    }


    @Override
    public List<LikedCountDTO> getLikedCountFromRedis() {
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
        List<LikedCountDTO> list = new ArrayList<>();
        while (cursor.hasNext()){
            Map.Entry<Object, Object> map = cursor.next();
            //将点赞数量存储在 LikedCountDT
            String key = (String)map.getKey();
            LikedCountDTO dto = new LikedCountDTO(key, (Integer) map.getValue());
            list.add(dto);
            //从Redis中删除这条记录
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);
        }
        return list;
    }

    @Override
    public Result getThumbUpCount(Integer postId) {
        boolean flag = redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,String.valueOf(postId));
        if(flag){
            Object hget = redisUtil.hget(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, String.valueOf(postId));
            return Result.success(hget);
        }else{
            int count = forumMapper.getThumbUpCount(postId);
            redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, String.valueOf(postId), count);
            return Result.success(count);
        }
    }

用户点赞的service LikedService:

package future.image.service;

import future.image.pojo.UserLike;
import future.image.utils.Result;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

public interface LikedService {

    /**
     * 保存点赞记录
     * @param userLike
     * @return
     */
    Result saveUserLike(UserLike userLike);



    /**
     * 根据被点赞人的id查询点赞列表(即查询都谁给这个人点赞过)
     * @param postId pageSize pageNum
     * @return Result
     */
    Result getLikedListByPostId(Integer postId, Integer pageSize,Integer pageNum);



    /**
     * 通过被点赞人和点赞人id查询是否存在点赞记录
     * @param likedUserId
     * @param likedPostId
     * @return
     */
    UserLike getByLikedUserIdAndLikedPostId(Integer likedUserId, Integer likedPostId);

    /**
     * 将Redis里的点赞数据存入数据库中
     */
    void transLikedFromRedis2DB();

    /**
     * 将Redis中的点赞数量数据存入数据库
     */
    void transLikedCountFromRedis2DB();

    /**
     * 点赞
     * */
    Result thumbUpForum(@Param("userId")Integer userId, @Param("postId")Integer postId);

    /**
     * 得到用户点赞状态
     */
    Result likeStatus(Integer postId,Integer userId);

}

及likedServiceImpl:


import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import future.image.dao.ForumMapper;
import future.image.dao.LikedMapper;
import future.image.dao.UserMapper;
import future.image.pojo.*;
import future.image.service.LikedService;
import future.image.service.RedisService;
import future.image.utils.RedisKeyUtils;
import future.image.utils.RedisUtil;
import future.image.utils.Result;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service("likedService")
public class LikedServiceImpl implements LikedService {


    @Resource
    RedisService redisService;

    @Resource
    LikedMapper likedMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    ForumMapper forumMapper;

    @Resource
    RedisUtil redisUtil;


    @Override
    public Result saveUserLike(UserLike userLike) {
        int f = likedMapper.savaUserLike(userLike);
        if(f != 1){
            return Result.fail("保存失败");
        }
        return Result.success();
    }



    @Override
    public Result getLikedListByPostId(Integer postId,Integer pageSize,Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        List<UserLike> list = likedMapper.getLikedListByPostId(postId);
        return Result.success(list);
    }



    @Override
    public UserLike getByLikedUserIdAndLikedPostId(Integer likedUserId, Integer likedPostId) {
        UserLike userlike = likedMapper.getByLikedUserIdAndLikedPostId(likedUserId,likedPostId);
        return userlike;
    }

    @Override
    public void transLikedFromRedis2DB() {
        List<UserLike> list = redisService.getLikedDataFromRedis();
        for (UserLike like : list) {
            UserLike ul = getByLikedUserIdAndLikedPostId(like.getUserId(), like.getPostId());
            if (ul == null){
                //没有记录,直接存入
                saveUserLike(like);
            }else{
                //有记录,需要更新
                ul.setStatus(like.getStatus());
                likedMapper.updateUserLike(ul);
            }
        }

    }

    @Override
    public void transLikedCountFromRedis2DB() {
        List<LikedCountDTO> list = redisService.getLikedCountFromRedis();
        if(list.size() == 0){
            return;
        }
        for (LikedCountDTO dto : list) {
            //点赞数量属于无关紧要的操作,出错无需抛异常
            Integer likeNum = dto.getCount();
            //更新点赞数量
            forumMapper.updateForumThumbUp(Integer.parseInt(dto.getId()),likeNum);
        }
    }

    @Override
    public Result thumbUpForum(Integer userId, Integer postId) {
        Object hget = redisUtil.hget(RedisKeyUtils.MAP_KEY_USER_LIKED, postId + "::" + userId);
        if(hget == null){
            redisService.saveLiked2Redis(String.valueOf(userId),String.valueOf(postId));
            redisService.incrementLikedCount(String.valueOf(postId));
            return Result.success(1);
        }else if("1".equals(hget.toString())){
            redisService.unlikeFromRedis(String.valueOf(userId),String.valueOf(postId));
            redisService.decrementLikedCount(String.valueOf(postId));
            return Result.success(0);
        }else{
            redisService.saveLiked2Redis(String.valueOf(userId),String.valueOf(postId));
            redisService.incrementLikedCount(String.valueOf(postId));
            return Result.success(1);
        }
    }

    @Override
    public Result likeStatus(Integer postId, Integer userId) {
        Object hget = redisUtil.hget(RedisKeyUtils.MAP_KEY_USER_LIKED, postId + "::" + userId);
        if(hget == null){
            Integer like = likedMapper.getUserLikeStatus(postId,userId);
            if(like == null){
                return  Result.success(0);
            }
            redisService.saveLiked2Redis(String.valueOf(postId),String.valueOf(userId));
            return Result.success(like);
        }else if("1".equals(hget.toString())){
            return Result.success(1);
        }else{
            return Result.success(0);
        }
    }
}

还有点赞功能的mapper,对数据库的操作LikedMapper:


import future.image.pojo.UserLike;

import java.util.List;

/**
 * @author zrl
 */
public interface LikedMapper {
    /**
     * 点赞保存
     */
    int savaUserLike(UserLike userLike);

    int saveAllUserLike(List<UserLike> userLike);

    int updateUserLike(UserLike userLike);

    List<UserLike> getLikedListByPostId(Integer likedUserId);

    UserLike getByLikedUserIdAndLikedPostId(Integer userId,Integer postId);

    Integer getUserLikeStatus(Integer postId,Integer userId);
}

总结:
每次考核都是对自己技术的提升,也对之前学习的东西有了实战经验,记忆更加深刻。在考核中锻炼自己的能力。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值