0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SpringBoot+Redis实现点赞功能的缓存和定时持久化(附源码)

Android编程精选 来源:CSDN 2023-02-09 16:38 次阅读

0.前言

本文基于Springboot利用Redis实现点赞功能的缓存和定时持久化接口

用户对浏览内容进行【点赞/取赞】,并发送【点赞/取赞】请求到后端,这些信息先存入Redis中缓存,再每隔两小时将Redis中的内容直接写入数据库持久化存储。

1.项目目录结构

5c54410e-a854-11ed-bfe3-dac502259ad0.png

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) 点赞数量
5c6435e6-a854-11ed-bfe3-dac502259ad0.png5c83b010-a854-11ed-bfe3-dac502259ad0.png

1.2 点赞

5c9b0eb8-a854-11ed-bfe3-dac502259ad0.png
  • 用户点赞信息,发送点赞请求到后端
  • 后端判断该点赞信息在Redis中的状态
    • Redis不进行存储,并提醒前端重复存储。
    • 更新/新增点赞信息
    • 更新/新增点赞量
    • 【不存在(没有对应key) 】|| 【取消点赞(即取出的status为1)】
    • 【点赞(即取出的status为0,此时相当于重复点赞行为)】
  • 一次点赞请求完毕

1.3 取消点赞

5cb6a150-a854-11ed-bfe3-dac502259ad0.png
  • 用户取消点赞信息,发送取消点赞请求到后端
  • 后端判断该点赞信息在Redis中的状态
    • 更新/新增点赞信息
    • 更新/新增点赞量
    • Redis不进行存储,并提醒前端重复存储。
    • 更新/新增点赞信息
    • 增加0条内容点赞量
    • 【不存在(没有对应key) 】
    • 【取消点赞(即取出的status为1,此时相当于重复取消点赞行为)】
    • 【点赞(即取出的status为0)】
  • 一次取消点赞请求完毕

2.核心代码实现

2.1 Redis封装

具体实现参考该博客,不在赘述。

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

2.2 工具类

1.时间戳转化为LocalDateTime

importjava.time.Instant;
importjava.time.LocalDateTime;
importjava.time.ZoneId;

/**
*工具类:将时间戳转化为LocalDateTime
*主要是因为redis不好存储LocalDateTime,存储timestamp方便一点,而且格式可以随意改变
*/
publicclassLocalDateTimeConvertUtil{
publicstaticLocalDateTimegetDateTimeOfTimestamp(longtimestamp){
Instantinstant=Instant.ofEpochMilli(timestamp);
ZoneIdzone=ZoneId.systemDefault();
returnLocalDateTime.ofInstant(instant,zone);
}
}

2.RedisKey处理类

publicclassRedisKeyUtils{
/**
*
保存用户点赞内容数据的key
*@date2021/9/2614:44
*/
publicstaticfinalStringMAP_KEY_USER_LIKED="MAP_USER_LIKED";
/**
*
保存内容被点赞数量的key
*@date2021/9/2614:44
*/
publicstaticfinalStringMAP_KEY_USER_LIKED_COUNT="MAP_USER_LIKED_COUNT";

/**
*拼接被点赞的内容id和点赞的人的id作为key。格式222222::333333
*@paraminfoId被点赞的内容id
*@paramlikeUserId点赞的人的id
*@return
*/
publicstaticStringgetLikedKey(StringinfoId,StringlikeUserId){
returninfoId+
"::"+
likeUserId;
}
}
2.3 DTO
//UserLikesDTO.java
@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassUserLikesDTO{
privateStringinfoId;
privateStringlikeUserId;
privateIntegerstatus;
privateLocalDateTimeupdateTime;
}

//UserLikeCountDTO.java
@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassUserLikeCountDTO{
privateStringinfoId;
privateIntegerlikeCount;
}
2.4 Service
  1. interface
//RedisService.java

importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;
importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;

importjava.util.List;

/**
*负责将数据写入Redis缓存
*/
publicinterfaceRedisService{
/**
*获取点赞状态
*@paraminfoId
*@paramlikeUserId
*/
IntegergetLikeStatus(StringinfoId,StringlikeUserId);
/**
*点赞。状态为1
*@paraminfoId
*@paramlikeUserId
*/
voidsaveLiked2Redis(StringinfoId,StringlikeUserId);

/**
*取消点赞。将状态改变为0
*@paraminfoId
*@paramlikeUserId
*/
voidunlikeFromRedis(StringinfoId,StringlikeUserId);

/**
*从Redis中删除一条点赞数据
*@paraminfoId
*@paramlikeUserId
*/
voiddeleteLikedFromRedis(StringinfoId,StringlikeUserId);

/**
*该内容的点赞数变化Δdelta
*@paraminfoId
*/
voidin_decrementLikedCount(StringinfoId,Integerdelta);

/**
*获取Redis中存储的所有点赞数据
*@return
*/
ListgetLikedDataFromRedis();

/**
*获取Redis中存储的所有点赞数量
*@return
*/
ListgetLikedCountFromRedis();
}
  1. implement
importcom.csu.edu.redisLikeDemo.common.CONSTANT;
importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;
importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;
importcom.csu.edu.redisLikeDemo.service.RedisService;
importcom.csu.edu.redisLikeDemo.util.LocalDateTimeConvertUtil;
importcom.csu.edu.redisLikeDemo.util.RedisKeyUtils;
importlombok.extern.slf4j.Slf4j;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.data.redis.core.Cursor;
importorg.springframework.data.redis.core.HashOperations;
importorg.springframework.data.redis.core.ScanOptions;
importorg.springframework.stereotype.Service;

importjava.time.LocalDateTime;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;

@Service("redisService")
@Slf4j
publicclassRedisServiceImplimplementsRedisService{

@Autowired
privateHashOperationsredisHash;//RedisHash

@Override
publicIntegergetLikeStatus(StringinfoId,StringlikeUserId){
if(redisHash.hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED,RedisKeyUtils.getLikedKey(infoId,likeUserId))){
HashMapmap=(HashMap)redisHash.get(RedisKeyUtils.MAP_KEY_USER_LIKED,RedisKeyUtils.getLikedKey(infoId,likeUserId));
return(Integer)map.get("status");
}
returnCONSTANT.LikedStatusEum.NOT_EXIST.getCode();
}

@Override
publicvoidsaveLiked2Redis(StringinfoId,StringlikeUserId){
//生成key
Stringkey=RedisKeyUtils.getLikedKey(infoId,likeUserId);
//封装value喜欢状态更新时间
HashMapmap=newHashMap<>();
map.put("status",CONSTANT.LikedStatusEum.LIKE.getCode());
map.put("updateTime",System.currentTimeMillis());

redisHash.put(RedisKeyUtils.MAP_KEY_USER_LIKED,key,map);
}

@Override
publicvoidunlikeFromRedis(StringinfoId,StringlikeUserId){
//生成key
Stringkey=RedisKeyUtils.getLikedKey(infoId,likeUserId);
//封装value喜欢状态更新时间
HashMapmap=newHashMap<>();
map.put("status",CONSTANT.LikedStatusEum.UNLIKE.getCode());
map.put("updateTime",System.currentTimeMillis());//存入当前时间戳

redisHash.put(RedisKeyUtils.MAP_KEY_USER_LIKED,key,map);
}

@Override
publicvoiddeleteLikedFromRedis(StringinfoId,StringlikeUserId){
Stringkey=RedisKeyUtils.getLikedKey(infoId,likeUserId);
redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED,key);
}

@Override
publicvoidin_decrementLikedCount(StringinfoId,Integerdelta){
redisHash.increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,infoId,delta);
}

@Override
publicListgetLikedDataFromRedis(){
//scan读取数据,比key匹配优雅
Cursor>cursor=redisHash.scan(RedisKeyUtils.MAP_KEY_USER_LIKED,ScanOptions.NONE);

Listlist=newArrayList<>();
while(cursor.hasNext()){
Map.Entryentry=cursor.next();
Stringkey=(String)entry.getKey();
//分离出infoId,likedPostId,解析value
String[]split=key.split("::");
StringinfoId=split[0];
StringlikeUserId=split[1];
HashMapmap=(HashMap)entry.getValue();
Integerstatus=(Integer)map.get("status");
longupdateTimeStamp=(long)map.get("updateTime");
LocalDateTimeupdateTime=LocalDateTimeConvertUtil.getDateTimeOfTimestamp(updateTimeStamp);//时间戳转为LocalDateTime

//组装成UserLike对象
UserLikesDTOuserLikesDTO=newUserLikesDTO(infoId,likeUserId,status,updateTime);
list.add(userLikesDTO);

//存到list后从Redis中清理缓存
redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED,key);
}
returnlist;
}

@Override
publicListgetLikedCountFromRedis(){
//scan读取数据,比key匹配优雅
Cursor>cursor=redisHash.scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,ScanOptions.NONE);
Listlist=newArrayList<>();
while(cursor.hasNext()){
Map.Entrymap=cursor.next();
//将点赞数量存储在LikedCountDT
Stringkey=(String)map.getKey();
UserLikeCountDTOdto=newUserLikeCountDTO(key,(Integer)map.getValue());
list.add(dto);
//从Redis中删除这条记录
redisHash.delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,key);
}
returnlist;
}
}
2.5 controller & API
  1. controller
importcom.csu.edu.redisLikeDemo.common.CommonResponse;
importcom.csu.edu.redisLikeDemo.service.LikeService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.PostMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test/")
publicclassLikeController{
@Autowired
privateLikeServicelikeService;

@PostMapping("like")
publicCommonResponselikeInfo(
StringinfoId,
StringuserId){
returnlikeService.likeInfo(infoId,userId);
}

@PostMapping("dislike")
publicCommonResponsedislikeInfo(
StringinfoId,
StringuserId){
returnlikeService.dislikeInfo(infoId,userId);
}
}

		
  1. 接口测试
5cde82ec-a854-11ed-bfe3-dac502259ad0.png5cde82ec-a854-11ed-bfe3-dac502259ad0.png5d0c3f52-a854-11ed-bfe3-dac502259ad0.png5d368bcc-a854-11ed-bfe3-dac502259ad0.png

3.Redis定时持久化

1.设计思路

1.1 数据库设计

#浏览内容表
DROPTABLEIFEXISTS`view_item`;
CREATETABLE`view_item`(
`id`varchar(32)CHARACTERSETutf8COLLATEutf8_general_ciNOTNULLCOMMENT'内容id(如文章、短视频等等)',
`create_user`varchar(50)CHARACTERSETutf8COLLATEutf8_general_ciNULLDEFAULTNULLCOMMENT'创建者',
`like_count`int(11)NULLDEFAULTNULLCOMMENT'点赞数',
`cmt_count`int(11)NULLDEFAULTNULLCOMMENT'评论数',
`share_count`int(11)NULLDEFAULTNULLCOMMENT'分享数',
`create_time`datetime(0)NULLDEFAULTNULLCOMMENT'创建时间',
`update_time`datetime(0)NULLDEFAULTNULLCOMMENT'更新时间',
PRIMARYKEY(`id`)USINGBTREE
)ENGINE=InnoDBCHARACTERSET=utf8COLLATE=utf8_general_ciROW_FORMAT=Dynamic;

SETFOREIGN_KEY_CHECKS=1;

#点赞-用户表
DROPTABLEIFEXISTS`user_likes`;
CREATETABLE`user_likes`(
`id`varchar(32)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULLCOMMENT'点赞信息ID',
`info_id`varchar(32)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNULLDEFAULTNULLCOMMENT'点赞对象id',
`like_user_id`varchar(32)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNULLDEFAULTNULLCOMMENT'点赞人ID',
`status`tinyint(4)NULLDEFAULT0COMMENT'0点赞1取消',
`create_time`datetime(0)NULLDEFAULTNULLCOMMENT'创建时间',
`update_time`datetime(0)NULLDEFAULTNULLCOMMENT'更新时间',
PRIMARYKEY(`id`)USINGBTREE,
UNIQUEINDEX`agdkey`(`like_user_id`,`info_id`)USINGBTREE
)ENGINE=InnoDBCHARACTERSET=utf8mb4COLLATE=utf8mb4_general_ciCOMMENT='点赞记录表'ROW_FORMAT=Dynamic;
5d4bba4c-a854-11ed-bfe3-dac502259ad0.png5d5d2052-a854-11ed-bfe3-dac502259ad0.png

1.2 流程

5d792c34-a854-11ed-bfe3-dac502259ad0.png
  1. 遍历Redis的【点赞信息】,仅改变数据库中点赞信息的状态
  2. 判断当前点赞信息是否在数据库中
  • 否,则更新数据
    • 数据库中新增点赞-用户记录
    • 更新内容的点赞量
    • 转到6
    • 转到第3步
  1. 判断数据库中的点赞状态与缓存中的点赞状态(status)
  • 一致
    • 状态不改变
    • 点赞数量-1(两种情况逻辑分析有差异,但是最终结果均为-1)
    • 结束
  • 不一致,则需要针对具体情况改变
    • 转到步骤4
  1. 判断数据库点赞状态
  • 已经点赞,需要更改为取消点赞
    • 数据库中修改为取消点赞状态
    • 更新缓存中的点赞数量-1(减去数据库中持久化的一个点赞量,一会儿缓存会和数据库点赞总量加和)
  • 取消点赞,需要更改
    • 数据库中修改为点赞状态
    • 无需更新缓存中的点赞数量,因为缓存中已经+1(即该点赞数据的点赞量)
  1. 将缓存【点赞数量】持久化并清理缓存 此处修改数据库中的点赞数量
  2. 完成缓存持久化

1.3定时写入

使用 Quartz redis 定时任务持久化存储到数据库


<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>

2.核心代码实现

2.1Bean

importcom.baomidou.mybatisplus.annotation.TableField;
importcom.baomidou.mybatisplus.annotation.TableId;
importcom.baomidou.mybatisplus.annotation.TableName;
importlombok.Data;

importjava.time.LocalDateTime;

@Data
@TableName("user_likes")
publicclassUserLikes{
@TableId
privateStringid;
@TableField("info_id")
privateStringinfoId;
@TableField("like_user_id")
privateStringlikeUserId;

privateIntegerstatus;

@TableField("create_time")
privateLocalDateTimecreateTime;
@TableField("update_time")
privateLocalDateTimeupdateTime;
}
importcom.baomidou.mybatisplus.annotation.TableField;
importcom.baomidou.mybatisplus.annotation.TableId;
importcom.baomidou.mybatisplus.annotation.TableName;
importlombok.Data;

importjava.time.LocalDateTime;

@Data
@TableName("view_item")
publicclassViewItem{
@TableId
privateStringid;
@TableField("create_user")
privateStringcreateUser;

@TableField("like_count")
privateIntegerlikeCount;
@TableField("cmt_count")
privateIntegercmtCount;
@TableField("share_count")
privateIntegershareCount;

@TableField("create_time")
privateLocalDateTimecreateTime;
@TableField("update_time")
privateLocalDateTimeupdateTime;
}

2.2 Service

  1. interface
importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;
importcom.csu.edu.redisLikeDemo.domain.UserLikes;

/**
*负责将Redis缓存中的数据持久化到数据库中
*/
publicinterfaceDBService{
/**
*保存点赞记录
*@paramuserLike
*@return
*/
Booleansave(UserLikesuserLike);
/**
*更新点赞记录
*@paramuserLike
*@return
*/
Booleanupdate(UserLikesuserLike);
/**
*根据内容的id查询点赞列表(即查询都谁给这个内容点赞过)
*@paraminfoId内容的id
*@return
*/
PagegetLikedListByInfoId(StringinfoId,intpageNum,intpageSize);

/**
*根据点赞人的id查询点赞列表(即查询这个人都给哪些内容点赞过)
*@paramlikeUserId
*@return
*/
PagegetLikedListByLikeUserId(StringlikeUserId,intpageNum,intpageSize);

/**
*通过被点赞内容和点赞人id查询是否存在点赞记录
*@paraminfoId
*@paramlikeUserId
*@return
*/
UserLikesgetByInfoIdAndLikeUserId(StringinfoId,StringlikeUserId);

/**
*将Redis里的点赞数据存入数据库中,True表示还需要进一步持久化,False表示数据库中已存在该数据,无需进一步持久化
*/
voidtransLikedFromRedis2DB();

/**
*将Redis中的点赞数量数据存入数据库
*/
voidtransLikedCountFromRedis2DB();
}
  1. implement
importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
importcom.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;
importcom.csu.edu.redisLikeDemo.common.CONSTANT;
importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikeCountDTO;
importcom.csu.edu.redisLikeDemo.domain.DTO.UserLikesDTO;
importcom.csu.edu.redisLikeDemo.domain.UserLikes;
importcom.csu.edu.redisLikeDemo.domain.ViewItem;
importcom.csu.edu.redisLikeDemo.mapper.UserLikesMapper;
importcom.csu.edu.redisLikeDemo.mapper.ViewItemMapper;
importcom.csu.edu.redisLikeDemo.service.DBService;
importcom.csu.edu.redisLikeDemo.service.RedisService;
importlombok.extern.slf4j.Slf4j;
importorg.apache.commons.collections4.CollectionUtils;
importorg.n3r.idworker.Sid;
importorg.springframework.beans.BeanUtils;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;

importjava.time.LocalDateTime;
importjava.util.HashMap;
importjava.util.List;

@Service("dbService")
@Slf4j
publicclassDBServiceImplimplementsDBService{

@Autowired
privateRedisServiceredisService;
@Autowired
privateUserLikesMapperuserLikesMapper;
@Autowired
privateViewItemMapperviewItemMapper;
@Autowired
privateSidsid;//Id生成器,利用idWorker产生唯一(不重复)自增式的id,可以根据需求选用其他方式,比如MyBatisPlus的自增

@Override
publicBooleansave(UserLikesuserLike){
introws=userLikesMapper.insert(userLike);
returnrows>0;
}

@Override
publicBooleanupdate(UserLikesuserLike){
UpdateWrapperupdateWrapper=newUpdateWrapper<>();
updateWrapper.set("status",userLike.getStatus());
updateWrapper.set("update_time",userLike.getUpdateTime());
updateWrapper.eq("id",userLike.getId());

introws=userLikesMapper.update(userLike,updateWrapper);
returnrows>0;
}

@Override
publicPagegetLikedListByInfoId(StringinfoId,intpageNum,intpageSize){
//分页获取喜欢列表信息
Pageresult=newPage<>();
result.setCurrent(pageNum);
result.setSize(pageSize);

//获取内容的id查询点赞列表
QueryWrapperqueryWrapper=newQueryWrapper();
queryWrapper.eq("info_id",infoId);
result=userLikesMapper.selectPage(result,queryWrapper);
log.info("获得内容的id查询点赞列表(即查询都有谁给这个内容点赞过)");
returnresult;
}

@Override
publicPagegetLikedListByLikeUserId(StringlikeUserId,intpageNum,intpageSize){
//分页获取喜欢列表信息
Pageresult=newPage<>();
result.setCurrent(pageNum);
result.setSize(pageSize);

//获取用户的id查询点赞列表
QueryWrapperqueryWrapper=newQueryWrapper();
queryWrapper.eq("like_user_id",likeUserId);
result=userLikesMapper.selectPage(result,queryWrapper);
log.info("获取点赞人的id查询点赞列表(即查询这个人都给哪些内容点赞过)");
returnresult;
}

@Override
publicUserLikesgetByInfoIdAndLikeUserId(StringinfoId,StringlikeUserId){
HashMapmap=newHashMap<>();
map.put("info_id",infoId);
map.put("like_user_id",likeUserId);
try{
UserLikesuserLikes=userLikesMapper.selectByMap(map).get(0);
log.info("通过被点赞人和点赞人id查询是否存在点赞记录");
returnuserLikes;
}catch(Exceptione){
log.info("当前查询的被点赞人和点赞人id不存在点赞记录");
returnnull;
}
}

@Override
publicvoidtransLikedFromRedis2DB(){
//批量获取缓存中的点赞数据
Listlist=redisService.getLikedDataFromRedis();
if(CollectionUtils.isEmpty(list))//为空,不写入
return;
for(UserLikesDTOitem:list){
UserLikesuserLikes=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.设置更改status2.redis中的count要-1(消除在数据库中自己的记录)
userLikes.setStatus(CONSTANT.LikedStatusEum.UNLIKE.getCode());
redisService.in_decrementLikedCount(item.getInfoId(),-1);
}elseif(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
publicvoidtransLikedCountFromRedis2DB(){
//获取缓存中内容的点赞数列表
Listlist=redisService.getLikedCountFromRedis();
if(CollectionUtils.isEmpty(list))//为空,不写入
return;
for(UserLikeCountDTOitem:list){
ViewItemviewItem=viewItemMapper.selectById(item.getInfoId());
if(viewItem!=null){//新增点赞数
IntegerlikeCount=viewItem.getLikeCount()+item.getLikeCount();
System.out.println("内容id不为空,更新内容点赞数量");
viewItem.setLikeCount(likeCount);

UpdateWrapperupdateWrapper=newUpdateWrapper<>();
updateWrapper.set("like_count",viewItem.getLikeCount());
updateWrapper.eq("id",viewItem.getId());
introws=viewItemMapper.update(viewItem,updateWrapper);
if(rows>0){
System.out.println("成功更新内容点赞数!");
return;
}
}
System.out.println("内容id不存在,无法将缓存数据持久化!");
}
}

privateUserLikesuserLikesDTOtoUserLikes(UserLikesDTOuserLikesDTO){
UserLikesuserLikes=newUserLikes();
userLikes.setId(sid.nextShort());
BeanUtils.copyProperties(userLikesDTO,userLikes);
userLikes.setCreateTime(LocalDateTime.now());
userLikes.setUpdateTime(LocalDateTime.now());
returnuserLikes;
}
}

3. 定时更新数据库

3.1 定时任务

importcom.csu.edu.redisLikeDemo.service.DBService;
importlombok.extern.slf4j.Slf4j;
importorg.quartz.JobExecutionContext;
importorg.quartz.JobExecutionException;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.scheduling.quartz.QuartzJobBean;

importjava.text.SimpleDateFormat;
importjava.util.Date;

/**
*定时任务
*/
@Slf4j
publicclassCronUtilextendsQuartzJobBean{
@Autowired
privateDBServicedbService;
privateSimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHHss");

/**
*执行的定时任务
*/
@Override
protectedvoidexecuteInternal(JobExecutionContextcontext)throwsJobExecutionException{
log.info("LikeTask--------{}",sdf.format(newDate()));

//将Redis里的点赞信息同步到数据库里
dbService.transLikedFromRedis2DB();
dbService.transLikedCountFromRedis2DB();
}
}

3.2 定时任务配置

设置每两个小时更新一次数据库

importcom.csu.edu.redisLikeDemo.util.CronUtil;
importorg.quartz.*;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;

/**
*开启定时任务持久化存储到数据库
*/
@Configuration
publicclassQuartzConfig{
privatestaticfinalStringLIKE_TASK_IDENTITY="LikeTaskQuartz";
@Bean
publicJobDetailquartzDetail(){
returnJobBuilder.newJob(CronUtil.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();
}

@Bean
publicTriggerquartzTrigger(){
SimpleScheduleBuilderscheduleBuilder=SimpleScheduleBuilder.simpleSchedule()
//.withIntervalInSeconds(20)//设置时间周期单位秒
.withIntervalInHours(2)//两个小时执行一次
.repeatForever();
returnTriggerBuilder.newTrigger().forJob(quartzDetail())
.withIdentity(LIKE_TASK_IDENTITY)
.withSchedule(scheduleBuilder)
.build();
}
}

4.项目源码地址 & 参考

项目源码:

  • https://github.com/WuYiheng-Og/redislike

参考:

  • https://cloud.tencent.com/developer/article/1445905

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

审核编辑 :李倩
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 缓存
    +关注

    关注

    1

    文章

    239

    浏览量

    26673
  • 数据库
    +关注

    关注

    7

    文章

    3795

    浏览量

    64366
  • spring
    +关注

    关注

    0

    文章

    340

    浏览量

    14340
  • Redis
    +关注

    关注

    0

    文章

    374

    浏览量

    10871
  • SpringBoot
    +关注

    关注

    0

    文章

    173

    浏览量

    177

原文标题:SpringBoot + Redis 实现点赞功能的缓存和定时持久化(附源码)

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Redis坚持持久方式概述

    Redis 持久
    发表于 09-25 17:04

    关于redis中数据存储的机制解析

    不同于memcached等完全基于内存的缓存中间件,Redis同时还提供了持久功能,这也是为什么Red
    发表于 09-02 10:46 1124次阅读
    关于<b class='flag-5'>redis</b>中数据存储的机制解析

    Springboot+redis操作多种实现

    一、Jedis,Redisson,Lettuce三者的区别共同点:都提供了基于Redis操作的Java API,只是封装程度,具体实现稍有不同。 不同点: 1.1、Jedis 是Redis的Java
    的头像 发表于 09-22 10:48 1825次阅读
    <b class='flag-5'>Springboot+redis</b>操作多种<b class='flag-5'>实现</b>

    Redis持久机制的实现原理和使用技巧

    Redis将数据存储在内存中,宕机或重启都会使内存数据全部丢失, Redis持久机制用来保证数据不会因为故障而丢失。
    的头像 发表于 09-13 16:42 1000次阅读

    Redis持久化分为两种:RDB和AOF

    Redis持久,一个老掉牙的问题,但是面试官就是喜欢问。这也是我们学Redis必会的一个知识
    的头像 发表于 02-21 09:22 692次阅读

    基于SpringBoot+Redis的转盘抽奖

    基于SpringBoot+Redis等技术实现转盘抽奖活动项目,含前端、后台及数据库文件
    的头像 发表于 02-28 14:24 1527次阅读
    基于<b class='flag-5'>SpringBoot+Redis</b>的转盘抽奖

    如何在SpringBoot中解决Redis缓存穿透等问题

    今天给大家介绍一下如何在SpringBoot中解决Redis缓存穿透、缓存击穿、缓存雪崩的问题。
    的头像 发表于 04-28 11:35 725次阅读

    如何用Springboot整合Redis

    docker exec -it redis redis-cli 注意:新版本redis6.0 默认开启了混合持久,重启
    的头像 发表于 10-08 14:56 581次阅读
    如何用<b class='flag-5'>Springboot</b>整合<b class='flag-5'>Redis</b>

    Redis持久机制介绍

    Redis持久机制? 为了能够重用Redis数据,或者防止系统故障,我们需要将Redis中的数据写入到磁盘空间中,即
    的头像 发表于 10-09 11:44 484次阅读
    <b class='flag-5'>Redis</b><b class='flag-5'>持久</b><b class='flag-5'>化</b>机制介绍

    Redis持久RDB方式介绍

    Redis持久 Redis是一个内存数据库,为了保证数据的持久性,它提供了两种持久
    的头像 发表于 10-09 14:56 508次阅读
    <b class='flag-5'>Redis</b><b class='flag-5'>持久</b><b class='flag-5'>化</b>RDB方式介绍

    redis两种持久方式的区别

    Redis是一款高性能、开源的键值存储数据库,它支持多种数据结构,并且具有高效的内存读写以及持久功能Redis
    的头像 发表于 12-04 11:12 520次阅读

    redis持久方式RDB和AOF的区别

    Redis 是一个高性能的键值对数据库,提供了两种持久方式:RDB 和 AOF。RDB 是将 Redis 的数据快照保存到磁盘上,而 AOF 则是将
    的头像 发表于 12-04 16:25 778次阅读

    redis持久机制和如何实现持久

    File)。 RDB是Redis默认采用的持久方式,它通过在指定时间间隔内将内存中的数据集快照写入到磁盘的二进制文件中,实现数据的
    的头像 发表于 12-05 10:02 456次阅读

    redis持久机制优缺点

    Redis是一个基于内存的高性能键值存储系统,它提供了多种持久机制来保证数据的可靠性。本文将详细介绍Redis持久
    的头像 发表于 12-05 10:03 715次阅读

    云容器redis持久配置

    云容器技术为企业带来了很多好处,包括高度可扩展性、灵活性和可移植性。其中一个常见的容器应用是Redis,一种高性能的键值对存储系统。在云环境中,保证Redis数据的
    的头像 发表于 12-05 10:07 507次阅读