Redis实现点赞与关注

Posted 一只小逸白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis实现点赞与关注相关的知识,希望对你有一定的参考价值。

目录

一、点赞

直接写入mysql

直接写入Mysql是最简单的做法。

做两个表即可,

  1. post_like

记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到;

  1. user_like_post

记录用户赞过了哪些文章, 当打开文章列表时,显示的有没有赞过的数据就在这里面;

缺点

  1. 数据库读写压力大
    热门文章会有很多用户点赞,甚至是短时间内被大量点赞, 直接操作数据库从长久来看不是很理想的做法。

redis直接存储

redis主要的特点就是快, 毕竟主要数据都在内存嘛;

优点

  1. 性能高

  2. 缓解数据库读写压力

其实我更多的在于缓解写压力, 真的读压力, 通过mysql主从甚至通过加入redis对热点数据做缓存都可以解决,写压力对于前面的方案确实是不大好使。

缺点

  1. 开发复杂

这个比直接写mysql的方案要复杂很多, 需要考虑的地方也很多;

  1. 不能保证数据安全性

不过对于我们点赞而已, 稍微丢失一点数据问题不大;

具体设计

redis设计部分:

post_set
在redis中弄一个set存放所有被点赞的文章

post_user_like_set_$post_id
对每个post以post_id作为key, 搞一个set存放所有对该post点赞的用户;

post_user_like_$post_id_$user_id
将每个用户对每个post的点赞情况放到一个hash里面去, hash的字段就

为啥用hash

只所以用hash是因为完全可以用hash来存储一个点赞的对象, 对应数据库的一行记录。

当然有同学会说用key, value也可以, 将所有的数据序列化(json_encode等)

后全部放到value里面去。 反复序列化也是一个很大的开销不是, hash可以很

方便的修改某个字段, 而序列化和反序列化的操作。

用户点赞/取消赞

获取user_id, post_id, 查询该用户是否已经点过赞, 已点过就取消点赞,

将用户的点赞/取消赞的情况记录在redis中, 具体为:

  1. 写入post_set

post_id写入post_set

  1. 写入post_user_like_set_$post_id

user_id写入post_user_like_set_$post_id

  1. 写入post_user_like_$post_id_$user_id

将用户点赞数据, 例如赞状态, post_id, user_id, ctime(操作时间), mtime(修改时间)写入post_user_like_KaTeX parse error: Expected 'EOF', got '' at position 8: post_id̲_user_id中

  1. 更新post_$post_id_counter

更新post_$post_id_counter, 这里的更新稍晚复杂一点, 需要和前面一样先获取当前用户是否对这个post点过赞

如果点过, 并且本次是取消赞, counter减一, 如果没点过, 本次是点赞, counter加一。

如果原来是取消赞的情况, 本次是点赞, counter加一。

二、关注

使用Redis有序集合可以做到根据关注的时间有序的取出列表,假设我的ID是me,别人的ID是other

1、添加关注

  1. 将对方id添加到自己的关注列表中;
    Redis::ZADD(“me:follow”, time(), other)
  2. 将自己的id添加到对方的粉丝列表中:
    Redis::ZADD(“other:fans”, time(), me)

2、取消关注

  1. 将对方id从自己的关注列表中移除;
    Redis::ZREM(“me:follow”, other)

  2. 将自己的id从对方的粉丝列表中移除:
    Redis::ZREM(“other:fans”, me)

3、 关注列表

  1. 查看我的关注列表:
    Redis::ZRANGE(“me:follow”, 0 , -1)

  2. 查看别人的把id换掉就可以
    Redis::ZRANGE(“other:follow”, 0 , -1)

4、 粉丝列表

  1. 查看我的粉丝列表:
    Redis::ZRANGE(“me:fans”, 0 , -1)

  2. 查看别人的把id换掉就可以
    Redis::ZRANGE(“other:fans”, 0 , -1)

5、人物关系

  1. 我单向关注他
  • 我的关注列表中有他(或他的粉丝列表中有我);
  • 我的粉丝列表中没有他(或他的关注列表中没有我)。

Redis::ZSCORE(“me:fans”, other) #未返回分数
Redis::ZSCORE(“me:follow”, other) #返回分数

  1. 他单向关注我
  • 我的关注列表中没有他(或他的粉丝列表中没有我);
  • 我的粉丝列表中有他(或他的关注列表中有我)。

Redis::ZSCORE(“other:fans”, me) #未返回分数
Redis::ZSCORE(“other:follow”, me) #返回分数

  1. 是否互粉
  • 我的关注列表中有他(或他的粉丝列表中有我);
  • 我的粉丝列表中有他(或他的关注列表中有我)。同时成立才为互粉。

Redis::ZSCORE(“me:fans”, other) #返回分数
Redis::ZSCORE(“me:follow”, other) #返回分数

6、 数量相关

  1. 我的关注数
    Redis::ZCARD(“me:follow”); #返回数量

  2. 我的粉丝数
    Redis::ZCARD(“me:fans”); #返回数量

7、 排序取出所有的人

  1. 根据关注的时间倒叙取出用户的id
    Redis::ZREVRANGE(“me:fans”, 0, -1, TRUE); #倒序取值

  2. 根据关注时间顺序取出用户的id
    Redis::ZRANGE(“me:fans”, 0, -1, TRUE); #顺序取值

!!!欢迎点赞收藏关注!!!

抽屉之Tornado实战--点赞与评论树

点赞

  • 点赞的过程:数字增加,并在后台点赞表记录数据

  • 需要发过去的数据:用户id,新闻id

  • 用户id从session里获得,那新闻id怎么获取呢?这想到分页是循环新闻列表来展示内容,循环的新闻id可以做为参数传入事件中(在事件里发送ajax请求),看前端代码:

                <div class="content-list" id="content_list">
                    {% for item in new_list %}
                    <div class="item">
                        <a onclick="Favor(this,{{item.nid}})">点赞9</a>
                    </div>
                    {% end %}
                </div>
  •  点赞数就在后台根据新闻id去统计对应的客户id数(点赞表中 )或者在新闻表在加一个字段--点赞数(favor_count),每次点了赞加个1

  • 没点赞的,点了+1,点了赞的,再点-1

 

  代码实现:

  1、后端render+  list【新闻1,新闻2...】  前端{{% for item in new_list %}}  点赞标签绑定onclick=‘func(this,{{item.nid}})’

  2、js:后台会返回一个操作编码,让前端判断,是加1操作,还是减1操作

function DoFavor(ths,nid){
//nid  新闻id
    //只有登录状态才能发送点赞ajax请求

    //获取特定登陆状态标签的属性值
    if($(‘#action_nav‘).attr(‘is-login‘) == ‘true‘){
        $.ajax({
            url:‘/favor‘,
            type:‘POST‘,
            data:{news_id:nid},
            dataType:‘json‘,
            success:function(arg){
                if(arg.status){
                    //获取新闻点赞数显示标签
                    var $favorCount = $("#favor_count_"+nid);
                    //获取点赞数
                    var c = parseInt($favorCount.text());
                    if(arg.code == 2301){
                        //更新显示
                        $favorCount.text(c+1);
                        //给点赞图像加上活动状态
                        $(ths).find(‘span‘).addClass("active");
                        //加动态效果
                        AddFavorAnimation(ths);
                    }else if(arg.code == 2302){
                        //更新显示
                        $favorCount.text(c-1);
                        //给点赞图像去除活动状态
                        $(ths).find(‘span‘).removeClass(‘active‘);
                        //动画效果
                    }
                }
            }
        })
    }
}

   3、后台判断处理

class FavorHandler(BaseRequestHandler):

    #装饰器主要做了一件---对用户登陆状态进行验证,如果没登录,就不会执行post方法
    @decrator.auth_login_json
    def psot(self,*args,**kwargs):
        #这对象相当于以前的字典,用封装错误信息,数据,状态
        rep = BaseResponse()

        news_id = self.get_argument("news_id",None)
        if not news_id:
            rep.summary = ‘新闻ID不能为空‘
        else:
            user_info_id = self.session[‘user_info‘][‘nid‘]
            #创建链接
            conn = ORM.session
            #去数据库看看有没有已经点赞
            has_favor = conn.query(ORM.Favor).filter(ORM.Favor.user_info_id == user_info_id,
                                                     ORM.Favor.news_id == new_id).count()
            #如果已赞,再点就是取消赞
            if has_favor:
                #取消赞就去点赞表里把那条数据删除
                conn.query(ORM.Favor).filter(ORM.Favor.user_inro_id == user_info_id,
                                             ORM.Favor.news_id == news_id).delete()
                #并在新闻表里修改点赞数-1
                conn.query(ORM.News).filter(ORM.News.nid == news_id).update(
                    {"favor_count":ORM.News.favor_count - 1},synchronize_session=‘evaluate‘
                )
                #设置编码
                rep.code = StatusCodeEnum.FavorMinus
            #如果没赞,加赞
            else:
                #给点赞表增加数据
                conn.add(ORM.Favor(user_info_id=user_info_id,news_id=news_id,ctime=datetime.datetime.now))
                #给新闻表的点赞跟新+1
                conn.query(ORM.News).filter(ORM.News.nid == news_id).update(
                    {‘favor_count‘:ORM.News.favor_count + 1},synchronize_session=‘evaluate‘
                )
          rep.code = StatusCodeEnum.FavorPlus conn.commit() conn.close() rep.status = True self.write(json.dumps(rep.__dict__))

   4、配置编码

FavorPlus = 2301
FavorMinus = 2302

class BaseRespinse:
    
    def __init__(self):
        self.status = False
        self.code = StatusCodeEnum.Success
        self.data = None
        self.summary = None
        self.message = {}

 

评论树

  • 评论树默认不展开,点击后展开,display:None
  • 刚开始看到的新闻是没有评论数据的,只有点击了后才有,本质上就偷偷发了请求给后台,然后把评论数据返回显示在页面上

以上是关于Redis实现点赞与关注的主要内容,如果未能解决你的问题,请参考以下文章

Redis如何高效实现点赞取消点赞功能

Redis如何高效实现点赞取消点赞功能

Redis应用2-Redis实现开发者头条页面点赞功能

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

Redis-PHP实战篇—Redis 数据结构使用场景

使用 Redis 缓存实现点赞和取消点赞