Redis实现点赞与关注
Posted 一只小逸白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis实现点赞与关注相关的知识,希望对你有一定的参考价值。
目录
一、点赞
直接写入mysql
直接写入Mysql是最简单的做法。
做两个表即可,
- post_like
记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到;
- user_like_post
记录用户赞过了哪些文章, 当打开文章列表时,显示的有没有赞过的数据就在这里面;
缺点
- 数据库读写压力大
热门文章会有很多用户点赞,甚至是短时间内被大量点赞, 直接操作数据库从长久来看不是很理想的做法。
redis直接存储
redis主要的特点就是快, 毕竟主要数据都在内存嘛;
优点
-
性能高
-
缓解数据库读写压力
其实我更多的在于缓解写压力, 真的读压力, 通过mysql主从甚至通过加入redis对热点数据做缓存都可以解决,写压力对于前面的方案确实是不大好使。
缺点
- 开发复杂
这个比直接写mysql的方案要复杂很多, 需要考虑的地方也很多;
- 不能保证数据安全性
不过对于我们点赞而已, 稍微丢失一点数据问题不大;
具体设计
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中, 具体为:
- 写入
post_set
将post_id
写入post_set
- 写入
post_user_like_set_$post_id
将user_id
写入post_user_like_set_$post_id
- 写入
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中
- 更新
post_$post_id_counter
更新post_$post_id_counter,
这里的更新稍晚复杂一点, 需要和前面一样先获取当前用户是否对这个post点过赞
如果点过, 并且本次是取消赞, counter减一, 如果没点过, 本次是点赞, counter加一。
如果原来是取消赞的情况, 本次是点赞, counter加一。
二、关注
使用Redis的有序集合可以做到根据关注的时间有序的取出列表,假设我的ID是me
,别人的ID是other
。
1、添加关注
- 将对方id添加到自己的关注列表中;
Redis::ZADD(“me:follow”, time(), other) - 将自己的id添加到对方的粉丝列表中:
Redis::ZADD(“other:fans”, time(), me)
2、取消关注
-
将对方id从自己的关注列表中移除;
Redis::ZREM(“me:follow”, other) -
将自己的id从对方的粉丝列表中移除:
Redis::ZREM(“other:fans”, me)
3、 关注列表
-
查看我的关注列表:
Redis::ZRANGE(“me:follow”, 0 , -1) -
查看别人的把id换掉就可以
Redis::ZRANGE(“other:follow”, 0 , -1)
4、 粉丝列表
-
查看我的粉丝列表:
Redis::ZRANGE(“me:fans”, 0 , -1) -
查看别人的把id换掉就可以
Redis::ZRANGE(“other:fans”, 0 , -1)
5、人物关系
- 我单向关注他
- 我的关注列表中有他(或他的粉丝列表中有我);
- 我的粉丝列表中没有他(或他的关注列表中没有我)。
Redis::ZSCORE(“me:fans”, other) #未返回分数
Redis::ZSCORE(“me:follow”, other) #返回分数
- 他单向关注我
- 我的关注列表中没有他(或他的粉丝列表中没有我);
- 我的粉丝列表中有他(或他的关注列表中有我)。
Redis::ZSCORE(“other:fans”, me) #未返回分数
Redis::ZSCORE(“other:follow”, me) #返回分数
- 是否互粉
- 我的关注列表中有他(或他的粉丝列表中有我);
- 我的粉丝列表中有他(或他的关注列表中有我)。同时成立才为互粉。
Redis::ZSCORE(“me:fans”, other) #返回分数
Redis::ZSCORE(“me:follow”, other) #返回分数
6、 数量相关
-
我的关注数
Redis::ZCARD(“me:follow”); #返回数量 -
我的粉丝数
Redis::ZCARD(“me:fans”); #返回数量
7、 排序取出所有的人
-
根据关注的时间倒叙取出用户的id
Redis::ZREVRANGE(“me:fans”, 0, -1, TRUE); #倒序取值 -
根据关注时间顺序取出用户的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实现点赞与关注的主要内容,如果未能解决你的问题,请参考以下文章