redis应用场景---记录文章的阅读次数

1. 场景说明

在阅读博客文章时,你可以看到一篇文章被阅读的次数,如果使用mysql, 那么在设计article表时,就必须设置一个view_count字段来记录这篇文章被阅读的次数。

但这种方式相比于使用redis,并不是一种好的办法,原因在于,每次更新view_count字段的值都是一个比较费力的过程。

  1. 首先,程序需要根据文章的id从数据库中查出view_count的值
  2. view_count = view_count + 1
  3. 更新数据库执行update操作

这3个步骤乍看起来倒是也蛮简单的,但第3步是非常容易出错的,假设网站并发量很大,同时有多个人阅读一篇文章,那么当程序执行上面这3步时就可能导致view_count没有被正确的修改,要知道我说网站并发量很大时,后台的服务就意味着是部署在多态机器上,当一个进程从数据库里查出来阅读次数是3,执行完第二步后,有另一个进程也执行更新操作,也从数据库里读出3,随后他们都进行update操作,可是最后,view_count的值是4, 而不是5。

这就是由于并发导致的数据没有被正确改写,和多线程需要互斥是一个道理。因此,你需要一点点的技巧,执行这样的sql

update article set view_count = 4 where id = 50 and view_count = 4

如果id为50的文章阅读次数已经被其他进程修改过了,那么你当前的这个sql就会执行失败,你只需要把1,2,3 三个步骤重新执行一遍就可以了,当然,也可能继续失败,因为其他进程有可能又再你前面执行了更新操作。。。。。。

现在,请思考,如果用redis来实现对文章阅读次数的记录,既简单,又方便

2. 思路分析

以文章的id做key,阅读次数做value,redis提供了incr 命令,可以让value值加1,众所周知,redis是单线程的,incr操作是原子性的,绝不会出现多次加1后实际结果与预期结果不相符的情况

3. 参考代码

from threading import Thread
from redis.client import Redis

r = Redis(host='127.0.0.1', port=6379, db=0, password='198671724zds')

def add_view():
    for i in range(10):
        r.incr('view::1')     # id为1的阅读次数加1

lst = []
for i in range(10):
    t = Thread(target=add_view)
    lst.append(t)

for t in lst:
    t.start()

for t in lst:
    t.join()

print(r.get('view::1'))   # 100

我用多线程来模拟多个用户阅读文章,尽管存在并发,由于redis单线程的特性使得incr的操作能够保证原子性。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案