从零开始搭建博客03----本周热议处理(redis 有序列表处理)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 本周热议,本周发表并且评论最多的文章排行,如果直接查询数据库的话很快就可以实现,只需要限定一下文章创建时间,然后根据评论数量倒叙取前几篇即可搞定。

本周热议,本周发表并且评论最多的文章排行,如果直接查询数据库的话很快就可以实现,只需要限定一下文章创建时间,然后根据评论数量倒叙取前几篇即可搞定。


但这里我们使用redis来完成。之前上课时候我们说过,排行榜功能,我们可以使用redis的有序集合zset来完成。现在我们就这个数据结构来完成本周热议的功能。


在编码之前,我们需要先来回顾一下zset的几个基本命令。


zrange key start stop [WITHSCORES]

withscores代表的是否显示顺序号 start和stop代表所在的位置的索引。可以这样理解:将集合元素依照顺序值升序排序再输出,start和stop限制遍历的限制范围

zincrby key increment member

为有序集 key 的成员 member 的 score 值加上增量 increment 。

ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。

默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和


实现步骤

查库获取最近7天的所有评论数量大于 0文章

把文章的评论数量作为有序集合的分数,文章id作为id存储到zset中

缓存文章到set中,评论数量作为排行标准

设置有效期为7天,因为超过了7天也就失去了时效性

具体代码实现

com.fly.service.impl.PostServiceImpl#initIndexWeekRank


 

@Override
    public void initIndexWeekRank() {
//        查库获取最近7天的所有文章
        List<Post> last7DayPosts = this.list(new QueryWrapper<Post>()
                .ge("created", DateUtil.offsetDay(new Date(), -7).toJdkDate())
                .gt("comment_count", 0)
                .select("id, title, user_id, comment_count, view_count, created"));
//        然后把文章的评论数量作为有序集合的分数,文章id作为ID存储到zset中。
        for (Post post : last7DayPosts) {
            String key = "day_rank" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_PATTERN);
//            设置有效期,7天之内有效
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;
//            缓存文章到set中,评论数量作为排行标准
            redisUtil.zSet(key, post.getId(), post.getCommentCount());
            //设置有效期
            redisUtil.expire(key, expireTime);
//            缓存文章基本信息(hash结构)
            this.hashCachePostIdAndTitle(post);
        }
//        7天阅读相加
        this.zUnionAndStroreLast7DaysForWeekRand();
    }

因为要显示文章的标题等基本信息

/**
     * hash结构缓存文章标题和id
     *
     * @param post
     */
    private void hashCachePostIdAndTitle(Post post) {
        boolean isExist = redisUtil.hasKey("rank_post_" + post.getId());
        if (!isExist) {
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;
//            缓存文章基本信息
            redisUtil.hset("rank_post_" + post.getId(), "post:id", post.getId(), expireTime);
            redisUtil.hset("rank_post_" + post.getId(), "post:title", post.getTitle(), expireTime);
        }
    }
    /**
     * 把最近7天的文章评论数量统计一下
     * 用于首页的7天评论排行榜
     */
    public void zUnionAndStroreLast7DaysForWeekRand() {
        String prifix = "day_rank";
        List<String> keys = new ArrayList<>();
        String key = prifix + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        for (int i = -7; i < 0; i++) {
            Date date = DateUtil.offsetDay(new Date(), i).toJdkDate();
            keys.add(prifix + DateUtil.format(date, DatePattern.PURE_DATE_PATTERN));
        }
        redisUtil.zUnionAndStore(key, keys, "last_week_rank");
    }

我们在项目启动之时初始化,代码如下:

e14a4bbe72bc1694dbc244f0856d152e_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png


增加评论数量

用户发表评论之后应该要数据库中的comment_count 加1,也要让缓存中数量加1,这样才能保证数据的一致性,在com.fly.controller.PostController#commentAdd 中

@Override
    public void incrZsetValueAndUnionForLastWeekRank(Long postId) {
        String dayRank = "day_rank" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
//        文章阅读加一
        redisUtil.zIncrementScore(dayRank, postId, 1);
        this.hashCachePostIdAndTitle(this.getById(postId));
//      重新union最近7天
        this.zUnionAndStroreLast7DaysForWeekRand();
    }

其实逻辑也和初始化差不多,首先给文章数量加一。集合名称是对应当天的。比如今天是12月21,对应的key就是day_rank:20181221。在这个上面给对应的文章id加一。这样每天都有评论这篇文章的话,我们再做交集处理,把每天的评论数量都加起来。得到的就是总的评论数量了。


前端引用的代码

common/templates.html

<!--本周热议-->
<div th:fragment="weekPopular">
    <dl class="fly-panel fly-list-one" id="post-hots">
        <dt class="fly-panel-title">本周热议</dt>
        <script id="hostDd" type="text/html">
            {{#  layui.each(d.list, function(index, item){ }}
            <dd>
                <a href="/post/{{item.id}}">{{item.title}}</a>
                <span><i class="iconfont icon-pinglun1"></i>{{item.comment_count}}</span>
            </dd>
            {{#  }); }}
            {{#  if(d.list.length === 0){ }}
            <div class="fly-none">没有相关数据</div>
            {{#  } }}
        </script>
    </dl>
    <script>
        layui.use(['laytpl'], function () {
            var laytpl = layui.laytpl;
            var post_hosts = document.getElementById("post-hots");
            var tpl = document.getElementById("hostDd").innerHTML;
            var data = {};
            $.ajax({
                url: "/post/hosts",
                async: false,
                success: function (res) {
                    if (res.code == 0) {
                        data.list = res.data;
                    }
                }
            });
            laytpl(tpl).render(data, function (html) {
                post_hosts.innerHTML += html;
            });
        });
    </script>
</div>

代码参考:

https://github.com/XWxiaowei/FlyBlog


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
8月前
|
域名解析 运维 负载均衡
【运维知识进阶篇】Tomcat集群实战之部署zrlog博客(Tomcat服务安装+静态资源挂载NFS+Nginx负载均衡+HTTPS证书+Redis会话保持)
【运维知识进阶篇】Tomcat集群实战之部署zrlog博客(Tomcat服务安装+静态资源挂载NFS+Nginx负载均衡+HTTPS证书+Redis会话保持)
254 1
|
10月前
|
存储 NoSQL JavaScript
【Node.js实战】一文带你开发博客项目之Express重构(初始化环境,处理 session,连接 redis)
【Node.js实战】一文带你开发博客项目之Express重构(初始化环境,处理 session,连接 redis)
148 0
|
10月前
|
NoSQL JavaScript 关系型数据库
【Node.js实战】一文带你开发博客项目之登录(对接完毕,cookie、session、redis各司其职)
【Node.js实战】一文带你开发博客项目之登录(对接完毕,cookie、session、redis各司其职)
110 0
|
JavaScript 前端开发 NoSQL
基于springboot+mysql+redis+bootstrap的精美个人技术博客网站
基于springboot+mysql+redis+bootstrap的精美个人技术博客网站
128 0
基于springboot+mysql+redis+bootstrap的精美个人技术博客网站
|
缓存 运维 NoSQL
收藏的博客 -- Redis学习
收藏的博客 -- Redis学习
125 0
|
14天前
|
NoSQL Linux Redis
06- 你们使用Redis是单点还是集群 ? 哪种集群 ?
**Redis配置:** 使用哨兵集群,结构为1主2从,加上3个哨兵节点,总计分布在3台Linux服务器上,提供高可用性。
60 0
|
22天前
|
负载均衡 监控 NoSQL
Redis的集群方案有哪些?
Redis集群包括主从复制(基础,手动故障恢复)、哨兵模式(自动高可用)和Redis Cluster(官方分布式解决方案,自动分片和容错)。此外,还有如Codis、Redisson和Twemproxy等第三方工具用于代理和负载均衡。选择方案需考虑应用场景、数据规模和并发需求。
50 2
|
28天前
|
NoSQL Redis
Redis集群(六):集群常用命令及说明
Redis集群(六):集群常用命令及说明
44 0