Redis构建分布式锁

2019-05-01 20:22:52王振洲

2、分别在两个浏览器中访问test.php文件

结果由上图可知,总共执行两次,count原本应该是二十万才对的,但实际上count等于十三万多,远远小于二十万,这是为什么呢?

由前面的内容可知,redis是采用单线程IO多路复用模型的。因此我们使用两个浏览器即为两个会话(A、B),取出、加1、存入这三个命令并不是原子操作,并且在执行取出、存入这两个redis命令时是哪个客户端先到就先执行。

例如:

1、此时count=120

2、A取出count=120,紧接着B的取出命令流到了,也将count=120取出

3、A取出后立即加1,并将count=121存回去

4、此时B也紧跟着,也将count=121存进去了

注意:

1、设置循环次数尽量大一点,太小的话,当在第一个浏览器执行完毕,第二个浏览器还没开始进行呢

2、必须要两个浏览器同时执行。假若在一个浏览器中同时执行两次test.php文件,不管是否同时执行,最终结果就是count=200000。因为在同一个浏览器中执行,都是属于同一个会话(所有命令都在同一个通道通过),所以redis会让先执行的十万次执行完,再接着执行其他的十万次。

4、事务解决与原子性操作解决

4.1、事务解决

更改后的test.php文件

<?php
header("content-type: text/html;charset=utf8;");
$start=time();
$redis=new Redis();
$redis->connect('192.168.95.11','6379');
for ($i=0; $i < 100000; $i++) 
{ 
 $redis->multi();
 $count=$redis->get('count');
 $count=$count+1;
 $redis->set('count',$count);
 $redis->exec();
}
$end=time();
echo "this OK<br/>";
echo "执行时间为:".($end-$start);
?>

执行结果失败,表名使用事务不能够解决此问题。

分析原因:

我们都知道当redis开启时,事务中的命令是不执行的,而是先将命令压入队列,然后当出现exec命令的时候,才会阻塞式的将所有的命令一个接一个的执行。

所以当使用PHP中的Redis类进行redis事务的时候,所有有关redis的命令都不会真正的执行,而仅仅是将命令发送到redis中进行存储起来。

因此下图中所圈到的$count实际上不是我们想要的数据,而是一个对象,因此test.php中11行出错。

查看对象count:

相关文章 大家在看