在阅读博客文章时,你可以看到一篇文章被阅读的次数,如果使用mysql, 那么在设计article表时,就必须设置一个view_count字段来记录这篇文章被阅读的次数。
但这种方式相比于使用redis,并不是一种好的办法,原因在于,每次更新view_count字段的值都是一个比较费力的过程。
这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来实现对文章阅读次数的记录,既简单,又方便
以文章的id做key,阅读次数做value,redis提供了incr 命令,可以让value值加1,众所周知,redis是单线程的,incr操作是原子性的,绝不会出现多次加1后实际结果与预期结果不相符的情况
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