千家信息网

PHP+Redis怎么实现点赞效果

发表于:2025-02-12 作者:千家信息网编辑
千家信息网最后更新 2025年02月12日,这篇文章主要介绍"PHP+Redis怎么实现点赞效果",在日常操作中,相信很多人在PHP+Redis怎么实现点赞效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"PHP
千家信息网最后更新 2025年02月12日PHP+Redis怎么实现点赞效果

这篇文章主要介绍"PHP+Redis怎么实现点赞效果",在日常操作中,相信很多人在PHP+Redis怎么实现点赞效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"PHP+Redis怎么实现点赞效果"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

前言

点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql(写了几百行的代码都还没写完,有毒)啦

数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等。

我这里所讲的功能都是基于我之前的项目去说的,所以有些地方可以不用管的,我主要是记录这个功能的实现思路,当你理解了,基本想用什么鬼语言写都一样的。

直接写入Mysql

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

做三个表即可,

  • comment_info

    记录文章的主要内容,主要有like_count,hate_count,score这三个字段是我们本次功能的主要字段。

  • comment_like

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

  • user_like_comment

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

缺点

  • 数据库读写压力大

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

redis存储随后批量刷回数据库

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

另外为啥我选择redis而不是memcache的主要原因在于redis支持更多的数据类型, 例如hash, set, zset等。

下面具体的会用到这几个类型。

优点

  • 性能高

  • 缓解数据库读写压力

    其实我更多的在于缓解写压力, 真的读压力, 通过mysql主从甚至通过加入redis对热点数据做缓存都可以解决,

    写压力对于前面的方案确实是不大好使。

缺点

  • 开发复杂

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

  • 不能保证数据安全性

    redis挂掉的时候会丢失数据, 同时不及时同步redis中的数据, 可能会在redis内存置换的时候被淘汰掉;

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

其实上面第二点缺点是可以避免的,这就涉及到redis 的一些设计模式,不懂没关系,我尽量详细的写,后面我会给出如何解决这个缺点。

设计功能前知识准备

  1.将要用到的redis数据类型(具体的类型说明,请看底部链接,有详细说明):

  • zset 这个类型主要用来做排序或者数字的增减,这里被用作like 和hate的数字记录,以及热度的记录。

  • set 这个是无序集合,主要用来记录今天需不需要更新,将今天被点赞(包括点讨厌)过的文章id记录下来,方便晚上或者有时间对这部分数据更新。

  • hash 这个是散列,主要用来存储数据以及索引。这里被用来记录用户对哪个文章点了什么,方便下次判断(我看过一些网上的介绍使用set来记录,那个也可以,但是本人觉得这样做更省空间,以及方便管理,再有就是hash的速度快)。

  • list 这个是队列大佬,我们的数据能不能 安全 回到mysql就靠它了。

  2.关于热度如何去判断:

  大家都知道,文章获得点赞数越高,文章的热度就越高,那么怎么判断呢?不就直接记录点赞数就行啦,但是对于最新的文章怎么办?例如有一篇文章一年前发布的,获得50个赞,有篇最新文章获得49个赞,但是按照上面所说的一年前的文章热度还比最新的高,这就不合理了,文章都是时效性,谁都想看最新最热的。

  so!我们要换个方法去处理这个时效性,绝大部分语言都有 时间戳 生成的方法,时间戳随着时间越新,数字越大,直接将时间戳初始化赋值给文章的score,这样最新的文章相比以前的文章就会靠前了。接着是点赞对score的影响,我们假设一天得到20个赞算是一天最热,一天60*60*24=86400秒,然后得到一个赞就是得到86400 / 20 = 4320分。具体数字看自己的业务需求定,我只是举例子而已。点hate当然也会减去相应的数字。


  1. class Good

  2. {

  3. public $redis = null;


  4. //60*60*24/20=4320,每个点赞得到的分数,反之即之。

  5. public $score = 4320;


  6. //点赞增加数,或者点hate增加数

  7. public $num = 1;


  8. //init redis

  9. public $redis_host = "127.0.0.1";

  10. public $redis_port = "6379";

  11. public $redis_pass = "";


  12. public function __construct()

  13. {

  14. $this->redis = new Redis();

  15. $this->redis->connect($this->redis_host,$this->redis_port);

  16. $this->reids->auth($this->redis_pass);

  17. }


  18. /**

  19. * @param int $user_id 用户id

  20. * @param int $type 点击的类型 1.点like,2.点hate

  21. * @param int $comment_id 文章id

  22. * @return string json;

  23. */

  24. public function click($user_id,$type,$comment_id)

  25. {

  26. //判断redis是否已经缓存了该文章数据

  27. //使用:分隔符对redis管理是友好的

  28. //这里使用redis zset-> zscore()方法

  29. if($this->redis->zscore("comment:like",$comment_id))

  30. {

  31. //已经存在

  32. //判断点的是什么

  33. if($type==1)

  34. {

  35. //判断以前是否点过,点的是什么?

  36. //redis hash-> hget()

  37. $rel = $this->redis->hget("comment:record",$user_id.":".$comment_id);

  38. if(!$rel)

  39. {

  40. //什么都没点过

  41. //点赞加1

  42. $this->redis->zincrby("comment:like",$this->num,$comment_id);

  43. //增加分数

  44. $this->redis->zincrby("comment:score",$this->score,$comment_id);

  45. //记录上次操作

  46. $this->redis->hset("comment:record",$user_id.":".$comment_id,$type);


  47. $data = array(

  48. "state" => 1,

  49. "status" => 200,

  50. "msg" => "like+1",

  51. );

  52. }

  53. else if($rel==$type)

  54. {

  55. //点过赞了

  56. //点赞减1

  57. $this->redis->zincrby("comment:like",-($this->num),$comment_id);

  58. //增加分数

  59. $this->redis->zincrby("comment:score",-($this->score),$comment_id);

  60. $data = array(

  61. "state" => 2,

  62. "status" => 200,

  63. "msg" => "like-1",

  64. );

  65. }

  66. else if($rel==2)

  67. {

  68. //点过hate

  69. //hate减1

  70. $this->redis->zincrby("comment:hate",-($this->num),$comment_id);

  71. //增加分数

  72. $this->redis->zincrby("comment:score",$this->score+$this->score,$comment_id);

  73. //点赞加1

  74. $this->redis->zincrby("comment:like",$this->num,$comment_id);

  75. //记录上次操作

  76. $this->redis->hset("comment:record",$user_id.":".$comment_id,$type);


  77. $data = array(

  78. "state" => 3,

  79. "status" => 200,

  80. "msg" => "like+1",

  81. );

  82. }

  83. }

  84. else if($type==2)

  85. {

  86. //点hate和点赞的逻辑是一样的。参看上面的点赞

  87. $rel = $this->redis->hget("comment:record",$user_id.":".$comment_id);

  88. if(!$rel)

  89. {

  90. //什么都没点过

  91. //点hate加1

  92. $this->redis->zincrby("comment:hate",$this->num,$comment_id);

  93. //减分数

  94. $this->redis->zincrby("comment:score",-($this->score),$comment_id);

  95. //记录上次操作

  96. $this->redis->hset("comment:record",$user_id.":".$comment_id,$type);


  97. $data = array(

  98. "state" => 4,

  99. "status" => 200,

  100. "msg" => "hate+1",

  101. );

  102. }

  103. else if($rel==$type)

  104. {

  105. //点过hate了

  106. //点hate减1

  107. $this->redis->zincrby("comment:hate",-($this->num),$comment_id);

  108. //增加分数

  109. $this->redis->zincrby("comment:score",$this->score,$comment_id);


  110. $data = array(

  111. "state" => 5,

  112. "status" => 200,

  113. "msg" => "hate-1",

  114. );

  115. return $data;

  116. }

  117. else if($rel==2)

  118. {

  119. //点过like

  120. //like减1

  121. $this->redis->zincrby("comment:like",-($this->num),$comment_id);

  122. //增加分数

  123. $this->redis->zincrby("comment:score",-($this->score+$this->score),$comment_id);

  124. //点hate加1

  125. $this->redis->zincrby("comment:hate",$this->num,$comment_id);


  126. $data = array(

  127. "state" => 6,

  128. "status" => 200,

  129. "msg" => "hate+1",

  130. );

  131. return $data;

  132. }

  133. }

  134. }

  135. else

  136. {

  137. //未存在

  138. if($type==1)

  139. {

  140. //点赞加一

  141. $this->redis->zincrby("comment:like",$this->num,$comment_id);

  142. //分数增加

  143. $this->redis->zincrby("comment:score",$this->score,$comment_id);

  144. $data = array(

  145. "state" => 7,

  146. "status" => 200,

  147. "msg" => "like+1",

  148. );

  149. }

  150. else if($type==2)

  151. {

  152. //点hate加一

  153. $this->redis->zincrby("comment:hate",$this->num,$comment_id);

  154. //分数减少

  155. $this->redis->zincrby("comment:score",-($this->score),$comment_id);


  156. $data = array(

  157. "state" => 8,

  158. "status" => 200,

  159. "msg" => "hate+1",

  160. );

  161. }

  162. //记录

  163. $this->redis->hset("comment:record",$user_id.":".$comment_id,$type);

  164. }


  165. //判断是否需要更新数据

  166. $this->ifUploadList($comment_id);


  167. return $data;

  168. }


  169. public function ifUploadList($comment_id)

  170. {

  171. date_default_timezone_set("Asia/Shanghai");

  172. $time = strtotime(date('Y-m-d H:i:s'));


  173. if(!$this->redis->sismember("comment:uploadset",$comment_id))

  174. {

  175. //文章不存在集合里,需要更新

  176. $this->redis->sadd("comment:uploadset",$comment_id);

  177. //更新到队列

  178. $data = array(

  179. "id" => $comment_id,

  180. "time" => $time,

  181. );

  182. $json = json_encode($data);

  183. $this->redis->lpush("comment:uploadlist",$json);

  184. }

  185. }

  186. }


  187. //调用

  188. $user_id = 100;

  189. $type = 1;

  190. $comment_id= 99;

  191. $good = new Good();

  192. $rel = $good->click($user_id,$type,$comment_id);

  193. var_dump($rel);

到此,关于"PHP+Redis怎么实现点赞效果"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0