天天看點

SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)

0.前言

本文基于Springboot利用Redis實作點贊功能的緩存和定時持久化接口。

使用者對浏覽内容進行【點贊/取贊】,并發送【點贊/取贊】請求到後端,這些資訊先存入Redis中緩存,再每隔兩小時将Redis中的内容直接寫入資料庫持久化存儲。

1.項目目錄結構

SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)

2.Redis緩存點贊消息

1.設計思路

使用者點贊一條資料,設定狀态為0,并且更新被點贊内容的likeCount+1

使用者取消點贊一條資料,設定狀态為1,并且更新被點贊内容的likeCount+0

1.1 Redis鍵值對設計

選用Hash(散列)存儲

點贊資訊

  • key: (String) 浏覽資訊id和點贊使用者id拼接而成, 分隔符為::
  • value: (HashMap) 存儲點贊狀态(0: 點贊 1:取消點贊)和更新時間的時間戳
  • key: "浏覽資訊id::點贊使用者id" value: {status: Integer, updateTime: long}

點贊數量

  • key: (String) 浏覽資訊id
  • value: (Integer) 點贊數量
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)

1.2 點贊

SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
  • 使用者點贊資訊,發送點贊請求到後端
  • 後端判斷該點贊資訊在Redis中的狀态
    • Redis不進行存儲,并提醒前端重複存儲。
    • 更新/新增點贊資訊
    • 更新/新增點贊量
    • 【不存在(沒有對應key) 】|| 【取消點贊(即取出的status為1)】
    • 【點贊(即取出的status為0,此時相當于重複點贊行為)】
  • 一次點贊請求完畢

1.3 取消點贊

SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
  • 使用者取消點贊資訊,發送取消點贊請求到後端
  • 後端判斷該點贊資訊在Redis中的狀态
    • 更新/新增點贊資訊
    • 更新/新增點贊量
    • Redis不進行存儲,并提醒前端重複存儲。
    • 更新/新增點贊資訊
    • 增加0條内容點贊量
    • 【不存在(沒有對應key) 】
    • 【取消點贊(即取出的status為1,此時相當于重複取消點贊行為)】
    • 【點贊(即取出的status為0)】
  • 一次取消點贊請求完畢

2.核心代碼實作

2.1 Redis封裝

具體實作參考該部落格,不在贅述。

https://www.cnblogs.com/caizhaokai/p/11037610.html

2.2 工具類

1.時間戳轉化為LocalDateTime

import java.time.Instant;import java.time.LocalDateTime;import java.time.ZoneId;/** * 工具類:将時間戳轉化為LocalDateTime * 主要是因為redis不好存儲LocalDateTime,存儲timestamp友善一點,而且格式可以随意改變 */public class LocalDateTimeConvertUtil {    public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {        Instant instant = Instant.ofEpochMilli(timestamp);        ZoneId zone = ZoneId.systemDefault();        return LocalDateTime.ofInstant(instant, zone);    }}           

2.RedisKey處理類

public class RedisKeyUtils {    /**     *     儲存使用者點贊内容資料的key     * @date 2021/9/26 14:44     */    public static final String MAP_KEY_USER_LIKED = "MAP_USER_LIKED";    /**     *     儲存内容被點贊數量的key     * @date 2021/9/26 14:44     */    public static final String MAP_KEY_USER_LIKED_COUNT = "MAP_USER_LIKED_COUNT";    /**     * 拼接被點贊的内容id和點贊的人的id作為key。格式 222222::333333     * @param infoId 被點贊的内容 id     * @param likeUserId 點贊的人的id     * @return     */    public static String getLikedKey(String infoId, String likeUserId){        return infoId +                "::" +                likeUserId;    }}           

2.3 DTO

// UserLikesDTO.java@Data@AllArgsConstructor@NoArgsConstructorpublic class UserLikesDTO {    private String infoId;    private String likeUserId;    private Integer status;    private LocalDateTime updateTime;}// UserLikeCountDTO.java@Data@AllArgsConstructor@NoArgsConstructorpublic class UserLikeCountDTO {    private String infoId;    private Integer likeCount;}           

2.4 Service

  1. interface
// RedisService.javaimport com.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;import com.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;import java.util.List;/** * 負責将資料寫入Redis緩存 */public interface RedisService {    /**     * 擷取點贊狀态     * @param infoId     * @param likeUserId     */    Integer getLikeStatus(String infoId, String likeUserId);    /**     * 點贊。狀态為1     * @param infoId     * @param likeUserId     */    void saveLiked2Redis(String infoId, String likeUserId);    /**     * 取消點贊。将狀态改變為0     * @param infoId     * @param likeUserId     */    void unlikeFromRedis(String infoId, String likeUserId);    /**     * 從Redis中删除一條點贊資料     * @param infoId     * @param likeUserId     */    void deleteLikedFromRedis(String infoId, String likeUserId);    /**     * 該内容的點贊數變化Δdelta     * @param infoId     */    void in_decrementLikedCount(String infoId, Integer delta);    /**     * 擷取Redis中存儲的所有點贊資料     * @return     */    List<UserLikesDTO> getLikedDataFromRedis();    /**     * 擷取Redis中存儲的所有點贊數量     * @return     */    List<UserLikeCountDTO> getLikedCountFromRedis();}           
  1. implement
import com.csu.edu.redisLikeDemo.common.CONSTANT;import com.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;import com.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;import com.csu.edu.redisLikeDemo.service.RedisService;import com.csu.edu.redisLikeDemo.util.LocalDateTimeConvertUtil;import com.csu.edu.redisLikeDemo.util.RedisKeyUtils;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.Cursor;import org.springframework.data.redis.core.HashOperations;import org.springframework.data.redis.core.ScanOptions;import org.springframework.stereotype.Service;import java.time.LocalDateTime;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Service("redisService")@Slf4jpublic class RedisServiceImpl implements RedisService {    @Autowired    private HashOperations<String, String, Object> redisHash;// Redis Hash    @Override    public Integer getLikeStatus(String infoId, String likeUserId) {        if (redisHash.hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(infoId, likeUserId))){            HashMap<String, Object> map = (HashMap<String, Object>) redisHash.get(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(infoId, likeUserId));            return (Integer) map.get("status");        }        return CONSTANT.LikedStatusEum.NOT_EXIST.getCode();    }    @Override    public void saveLiked2Redis(String infoId, String likeUserId) {        // 生成key        String key = RedisKeyUtils.getLikedKey(infoId, likeUserId);        // 封裝value 喜歡狀态 更新時間        HashMap<String,Object> map = new HashMap<>();        map.put("status",CONSTANT.LikedStatusEum.LIKE.getCode());        map.put("updateTime", System.currentTimeMillis());        redisHash.put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, map);    }    @Override    public void unlikeFromRedis(String infoId, String likeUserId) {        // 生成key        String key = RedisKeyUtils.getLikedKey(infoId, likeUserId);        // 封裝value 喜歡狀态 更新時間        HashMap<String,Object> map = new HashMap<>();        map.put("status",CONSTANT.LikedStatusEum.UNLIKE.getCode());        map.put("updateTime", System.currentTimeMillis());// 存入目前時間戳        redisHash.put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, map);    }    @Override    public void deleteLikedFromRedis(String infoId, String likeUserId) {        String key = RedisKeyUtils.getLikedKey(infoId, likeUserId);        redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);    }    @Override    public void in_decrementLikedCount(String infoId, Integer delta) {        redisHash.increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, infoId, delta);    }    @Override    public List<UserLikesDTO> getLikedDataFromRedis() {        // scan 讀取資料,比key比對優雅        Cursor<Map.Entry<String, Object>> cursor = redisHash.scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);        List<UserLikesDTO> list = new ArrayList<>();        while (cursor.hasNext()){            Map.Entry<String, Object> entry = cursor.next();            String key = (String) entry.getKey();            //分離出 infoId,likedPostId, 解析value            String[] split = key.split("::");            String infoId = split[0];            String likeUserId = split[1];            HashMap<String, Object> map = (HashMap<String, Object>) entry.getValue();            Integer status = (Integer) map.get("status");            long updateTimeStamp = (long) map.get("updateTime");            LocalDateTime updateTime = LocalDateTimeConvertUtil.getDateTimeOfTimestamp(updateTimeStamp);// 時間戳轉為LocalDateTime            //組裝成 UserLike 對象            UserLikesDTO userLikesDTO = new UserLikesDTO(infoId, likeUserId, status, updateTime);            list.add(userLikesDTO);            //存到 list 後從 Redis 中清理緩存            redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);        }        return list;    }    @Override    public List<UserLikeCountDTO> getLikedCountFromRedis() {        // scan 讀取資料,比key比對優雅        Cursor<Map.Entry<String, Object>> cursor = redisHash.scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);        List<UserLikeCountDTO> list = new ArrayList<>();        while (cursor.hasNext()){            Map.Entry<String, Object> map = cursor.next();            //将點贊數量存儲在 LikedCountDT            String key = (String)map.getKey();            UserLikeCountDTO dto = new UserLikeCountDTO(key, (Integer) map.getValue());            list.add(dto);            //從Redis中删除這條記錄            redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);        }        return list;    }}           

2.5 controller & API

  1. controller
import com.csu.edu.redisLikeDemo.common.CommonResponse;import com.csu.edu.redisLikeDemo.service.LikeService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test/")public class LikeController {    @Autowired    private LikeService likeService;    @PostMapping("like")    public CommonResponse<Object> likeInfo(            String infoId,            String userId){        return likeService.likeInfo(infoId, userId);    }    @PostMapping("dislike")    public CommonResponse<Object> dislikeInfo(            String infoId,            String userId){        return likeService.dislikeInfo(infoId, userId);    }}           
  1. 接口測試
牛逼啊!接私活必備的 N 個開源項目!趕快收藏           
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)

3.Redis定時持久化

1.設計思路

1.1 資料庫設計

# 浏覽内容表DROP TABLE IF EXISTS `view_item`;CREATE TABLE `view_item`  (  `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '内容id(如文章、短視訊等等)',  `create_user` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '建立者',  `like_count` int(11) NULL DEFAULT NULL COMMENT '點贊數',  `cmt_count` int(11) NULL DEFAULT NULL COMMENT '評論數',  `share_count` int(11) NULL DEFAULT NULL COMMENT '分享數',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '建立時間',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新時間',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;# 點贊-使用者表DROP TABLE IF EXISTS `user_likes`;CREATE TABLE `user_likes`  (  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '點贊資訊ID',  `info_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '點贊對象id',  `like_user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '點贊人ID',  `status` tinyint(4) NULL DEFAULT 0 COMMENT '0 點贊 1 取消 ',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '建立時間',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新時間',  PRIMARY KEY (`id`) USING BTREE,  UNIQUE INDEX `agdkey`(`like_user_id`, `info_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '點贊記錄表' ROW_FORMAT = Dynamic;           
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)

1.2 流程

SpringBoot + Redis 實作點贊功能的緩存和定時持久化(附源碼)
  1. 周遊Redis的【點贊資訊】,僅改變資料庫中點贊資訊的狀态
  2. 判斷目前點贊資訊是否在資料庫中
  • 否,則更新資料
    • 資料庫中新增點贊-使用者記錄
    • 更新内容的點贊量
    • 轉到6
    • 轉到第3步
  1. 判斷資料庫中的點贊狀态與緩存中的點贊狀态(status)
  • 一緻
    • 狀态不改變
    • 點贊數量-1(兩種情況邏輯分析有差異,但是最終結果均為-1)
    • 結束
  • 不一緻,則需要針對具體情況改變
    • 轉到步驟4
  1. 判斷資料庫點贊狀态
  • 已經點贊,需要更改為取消點贊
    • 資料庫中修改為取消點贊狀态
    • 更新緩存中的點贊數量-1(減去資料庫中持久化的一個點贊量,一會兒緩存會和資料庫點贊總量加和)
  • 取消點贊,需要更改
    • 資料庫中修改為點贊狀态
    • 無需更新緩存中的點贊數量,因為緩存中已經+1(即該點贊資料的點贊量)
  1. 将緩存【點贊數量】持久化并清理緩存 此處修改資料庫中的點贊數量
  2. 完成緩存持久化

1.3定時寫入

使用 Quartz redis 定時任務持久化存儲到資料庫

<!-- Quartz redis定時任務持久化存儲到資料庫 --><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-quartz</artifactId></dependency>           

2.核心代碼實作

2.1Bean

import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableName;import lombok.Data;import java.time.LocalDateTime;@Data@TableName("user_likes")public class UserLikes {    @TableId    private String id;    @TableField("info_id")    private String infoId;    @TableField("like_user_id")    private String likeUserId;    private Integer status;    @TableField("create_time")    private LocalDateTime createTime;    @TableField("update_time")    private LocalDateTime updateTime;}           
import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableName;import lombok.Data;import java.time.LocalDateTime;@Data@TableName("view_item")public class ViewItem {    @TableId    private String id;    @TableField("create_user")    private String createUser;    @TableField("like_count")    private Integer likeCount;    @TableField("cmt_count")    private Integer cmtCount;    @TableField("share_count")    private Integer shareCount;    @TableField("create_time")    private LocalDateTime createTime;    @TableField("update_time")    private LocalDateTime updateTime;}           

2.2 Service

  1. interface
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.csu.edu.redisLikeDemo.domain.UserLikes;/** * 負責将Redis緩存中的資料持久化到資料庫中 */public interface DBService {    /**     * 儲存點贊記錄     * @param userLike     * @return     */    Boolean save(UserLikes userLike);    /**     * 更新點贊記錄     * @param userLike     * @return     */    Boolean update(UserLikes userLike);    /**     * 根據内容的id查詢點贊清單(即查詢都誰給這個内容點贊過)     * @param infoId 内容的id     * @return     */    Page<UserLikes> getLikedListByInfoId(String infoId, int pageNum, int pageSize);    /**     * 根據點贊人的id查詢點贊清單(即查詢這個人都給哪些内容點贊過)     * @param likeUserId     * @return     */    Page<UserLikes> getLikedListByLikeUserId(String likeUserId, int pageNum, int pageSize);    /**     * 通過被點贊内容和點贊人id查詢是否存在點贊記錄     * @param infoId     * @param likeUserId     * @return     */    UserLikes getByInfoIdAndLikeUserId(String infoId, String likeUserId);    /**     * 将Redis裡的點贊資料存入資料庫中,True 表示還需要進一步持久化, False表示資料庫中已存在該資料,無需進一步持久化     */    void transLikedFromRedis2DB();    /**     * 将Redis中的點贊數量資料存入資料庫     */    void transLikedCountFromRedis2DB();}           
  1. implement
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.csu.edu.redisLikeDemo.common.CONSTANT;import com.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;import com.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;import com.csu.edu.redisLikeDemo.domain.UserLikes;import com.csu.edu.redisLikeDemo.domain.ViewItem;import com.csu.edu.redisLikeDemo.mapper.UserLikesMapper;import com.csu.edu.redisLikeDemo.mapper.ViewItemMapper;import com.csu.edu.redisLikeDemo.service.DBService;import com.csu.edu.redisLikeDemo.service.RedisService;import lombok.extern.slf4j.Slf4j;import org.apache.commons.collections4.CollectionUtils;import org.n3r.idworker.Sid;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.time.LocalDateTime;import java.util.HashMap;import java.util.List;@Service("dbService")@Slf4jpublic class DBServiceImpl implements DBService {    @Autowired    private RedisService redisService;    @Autowired    private UserLikesMapper userLikesMapper;    @Autowired    private ViewItemMapper viewItemMapper;    @Autowired    private Sid sid;// Id生成器,利用idWorker産生唯一(不重複)自增式的id,可以根據需求選用其他方式,比如MyBatisPlus的自增    @Override    public Boolean save(UserLikes userLike) {        int rows = userLikesMapper.insert(userLike);        return rows > 0;    }    @Override    public Boolean update(UserLikes userLike) {        UpdateWrapper<UserLikes> updateWrapper = new UpdateWrapper<>();        updateWrapper.set("status", userLike.getStatus());        updateWrapper.set("update_time",userLike.getUpdateTime());        updateWrapper.eq("id",userLike.getId());        int rows = userLikesMapper.update(userLike,updateWrapper);        return rows > 0;    }    @Override    public Page<UserLikes> getLikedListByInfoId(String infoId, int pageNum, int pageSize) {        // 分頁擷取喜歡清單資訊        Page<UserLikes> result = new Page<>();        result.setCurrent(pageNum);        result.setSize(pageSize);        // 擷取内容的id查詢點贊清單        QueryWrapper<UserLikes> queryWrapper = new QueryWrapper();        queryWrapper.eq("info_id",infoId);        result = userLikesMapper.selectPage(result, queryWrapper);        log.info("獲得内容的id查詢點贊清單(即查詢都有誰給這個内容點贊過)");        return result;    }    @Override    public Page<UserLikes> getLikedListByLikeUserId (String likeUserId, int pageNum, int pageSize) {        // 分頁擷取喜歡清單資訊        Page<UserLikes> result = new Page<>();        result.setCurrent(pageNum);        result.setSize(pageSize);        // 擷取使用者的id查詢點贊清單        QueryWrapper<UserLikes> queryWrapper = new QueryWrapper();        queryWrapper.eq("like_user_id", likeUserId);        result = userLikesMapper.selectPage(result, queryWrapper);        log.info("擷取點贊人的id查詢點贊清單(即查詢這個人都給哪些内容點贊過)");        return result;    }    @Override    public UserLikes getByInfoIdAndLikeUserId (String infoId, String likeUserId) {        HashMap<String, Object> map = new HashMap<>();        map.put("info_id",infoId);        map.put("like_user_id",likeUserId);        try{            UserLikes userLikes = userLikesMapper.selectByMap(map).get(0);            log.info("通過被點贊人和點贊人id查詢是否存在點贊記錄");            return userLikes;        }catch (Exception e){            log.info("目前查詢的被點贊人和點贊人id不存在點贊記錄");            return null;        }    }    @Override    public void transLikedFromRedis2DB() {        // 批量擷取緩存中的點贊資料        List<UserLikesDTO> list = redisService.getLikedDataFromRedis();        if (CollectionUtils.isEmpty(list))// 為空,不寫入            return;        for (UserLikesDTO item: list){            UserLikes userLikes = getByInfoIdAndLikeUserId(item.getInfoId(), item.getLikeUserId());// 在資料庫中查詢            if (userLikes == null) {// 無記錄,新增                if(!save(userLikesDTOtoUserLikes(item))){                    log.info("新增點贊資料失敗!");                    return;                // System.out.println("緩存記錄寫入資料庫失敗!請重試");                }            }else {// 有記錄,更新                // 判斷資料庫中點贊狀态與緩存中點贊狀态一緻性                if (userLikes.getStatus()==item.getStatus()){// 一緻,無需持久化,點贊數量-1                    redisService.in_decrementLikedCount(item.getInfoId(), -1);                }else{// 不一緻                    if (userLikes.getStatus()== CONSTANT.LikedStatusEum.LIKE.getCode()){// 在資料庫中已經是點贊,則取消點贊,同時記得redis中的count-1                        // 之前是點贊,現在改為取消點贊 1.設定更改status 2. redis中的count要-1(消除在資料庫中自己的記錄)                        userLikes.setStatus(CONSTANT.LikedStatusEum.UNLIKE.getCode());                        redisService.in_decrementLikedCount(item.getInfoId(), -1);                    } else if (userLikes.getStatus()== CONSTANT.LikedStatusEum.UNLIKE.getCode()) {// 未點贊,則點贊,修改點贊狀态和點贊資料+1                        userLikes.setStatus(CONSTANT.LikedStatusEum.LIKE.getCode());                        redisService.in_decrementLikedCount(item.getInfoId(), 1);                    }                    userLikes.setUpdateTime(LocalDateTime.now());                    if(!update(userLikes)){// 更新點贊資料                        log.info("更新點贊資料失敗!");                        return;                    // System.out.println("緩存記錄更新資料庫失敗!請重試");                    }                }            }        }    }    @Override    public void transLikedCountFromRedis2DB() {// 擷取緩存中内容的點贊數清單        List<UserLikeCountDTO> list = redisService.getLikedCountFromRedis();        if (CollectionUtils.isEmpty(list))// 為空,不寫入            return;        for (UserLikeCountDTO item: list){            ViewItem viewItem = viewItemMapper.selectById(item.getInfoId());            if (viewItem != null) {// 新增點贊數                Integer likeCount = viewItem.getLikeCount() + item.getLikeCount();                System.out.println("内容id不為空,更新内容點贊數量");                viewItem.setLikeCount(likeCount);                UpdateWrapper<ViewItem> updateWrapper = new UpdateWrapper<>();                updateWrapper.set("like_count", viewItem.getLikeCount());                updateWrapper.eq("id", viewItem.getId());                int rows = viewItemMapper.update(viewItem, updateWrapper);                if (rows > 0) {                    System.out.println("成功更新内容點贊數!");                    return;                }            }            System.out.println("内容id不存在,無法将緩存資料持久化!");        }    }    private UserLikes userLikesDTOtoUserLikes(UserLikesDTO userLikesDTO){        UserLikes userLikes = new UserLikes();        userLikes.setId(sid.nextShort());        BeanUtils.copyProperties(userLikesDTO,userLikes);        userLikes.setCreateTime(LocalDateTime.now());        userLikes.setUpdateTime(LocalDateTime.now());        return userLikes;    }}           

3. 定時更新資料庫

3.1 定時任務

import com.csu.edu.redisLikeDemo.service.DBService; import lombok.extern.slf4j.Slf4j;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.quartz.QuartzJobBean;import java.text.SimpleDateFormat;import java.util.Date;/** * 定時任務 */@Slf4jpublic class CronUtil extends QuartzJobBean {    @Autowired    private DBService dbService;    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    /**     * 執行的定時任務     */    @Override    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {        log.info("LikeTask-------- {}", sdf.format(new Date()));        //将 Redis 裡的點贊資訊同步到資料庫裡        dbService.transLikedFromRedis2DB();        dbService.transLikedCountFromRedis2DB();    }}           

3.2 定時任務配置

設定每兩個小時更新一次資料庫

import com.csu.edu.redisLikeDemo.util.CronUtil;import org.quartz.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * 開啟定時任務持久化存儲到資料庫 */@Configurationpublic class QuartzConfig {    private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";    @Bean    public JobDetail quartzDetail(){        return JobBuilder.newJob(CronUtil.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();    }    @Bean    public Trigger quartzTrigger(){        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()//                .withIntervalInSeconds(20)  //設定時間周期機關秒                .withIntervalInHours(2)  //兩個小時執行一次                .repeatForever();        return TriggerBuilder.newTrigger().forJob(quartzDetail())                .withIdentity(LIKE_TASK_IDENTITY)                .withSchedule(scheduleBuilder)                .build();    }}           

4.項目源碼位址 & 參考

項目源碼:

https://github.com/WuYiheng-Og/redislike
原文連結:https://mp.weixin.qq.com/s/qSM0SE2XI7ZsUCFHEr4IaQ

繼續閱讀