博客项目目录: 请戳这里
准备
需求:进入文章详情页之后,阅读量加1,并且通过缓存实现,定时将缓存中的阅读量同步到数据库
分析:首先查看缓存里有没有文章阅读信息,如果有,直接缓存加1;如果没有,则数据库里对应数据加1,然后同步到缓存。最后设置一个定时任务,每分钟从缓存将阅读量同步到数据库。
1.PostController设置文章阅读量
2.PostService定义相应的接口
public interface PostService extends IService<Post> {
void putViewCount(PostVo vo);
}
3.Impl层进行实现
/**
* 设置文章阅读量
* @param vo
*/
@Override
public void putViewCount(PostVo vo) {
String key = "rank:post:" + vo.getId();
// 1、从缓存中获取viewcount
Integer viewCount = (Integer) redisUtil.hget(key, "post:viewCount");
// 2、如果没有,就先从实体里面获取,再加一
if(viewCount != null) {
vo.setViewCount(viewCount + 1);
}
else {
vo.setViewCount(vo.getViewCount() + 1);
}
// 3、同步到缓存里面
redisUtil.hset(key, "post:viewCount", vo.getViewCount());
}
4.启动项目,进行测试
可以发现,每刷新一次浏览器,阅读量加1
5.实现定时任务
步骤:
- 获取缓存中含有阅读量的文章id集合
- 根据id查找需要更新的文章
- 如果同步成功,清空缓存里的阅读量
代码:
@Component
public class ViewCountSyncTask {
@Autowired
RedisUtil redisUtil;
@Autowired
RedisTemplate redisTemplate;
@Autowired
PostService postService;
@Scheduled(cron = "0/5 * * * * *") //每5秒同步
public void task() {
Set<String> keys = redisTemplate.keys("rank:post:*");
//获取缓存中含有阅读量的文章id集合
List<String> ids = new ArrayList<>();
for (String key : keys) {
if(redisUtil.hHasKey(key, "post:viewCount")){
ids.add(key.substring("rank:post:".length()));
}
}
if(ids.isEmpty()) return;
// 根据id查找需要更新的文章
List<Post> posts = postService.list(new QueryWrapper<Post>().in("id", ids));
posts.stream().forEach((post) ->{
Integer viewCount = (Integer) redisUtil.hget("rank:post:" + post.getId(), "post:viewCount");
post.setViewCount(viewCount);
});
if(posts.isEmpty()) return;
boolean isSucc = postService.updateBatchById(posts);
//如果同步成功,清空缓存里的阅读量
if(isSucc) {
ids.stream().forEach((id) -> {
redisUtil.hdel("rank:post:" + id, "post:viewCount");
System.out.println(id + "---------------------->同步成功");
});
}
}
}
在启动类加以下注解:
@EnableScheduling
原来的阅读量:
6.重新启动项目,进入文章,刷新浏览器
结果表明,阅读量成功从缓存同步到数据库
参考资料:
https://github.com/MarkerHub/eblog