小编给大家分享一下怎么利用Redis锁解决高并发,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

redis技术的使用:

redis真的是一个很好的技术,它可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动。。。

redis之所以能解决高并发的原因是它可以直接访问内存,而以往我们用的是数据库(硬盘),提高了访问效率,解决了数据库服务器压力。

为什么redis的地位越来越高,我们为何不选择memcache,这是因为memcache只能存储字符串,而redis存储类型很丰富(例如有字符串、LIST、SET等),memcache每个值最大只能存储1M,存储资源非常有限,十分消耗内存资源,而redis可以存储1G,最重要的是memcache它不如redis安全,当服务器发生故障或者意外关机等情况时,redsi会把内存中的数据备份到硬盘中,而memcache所存储的东西全部丢失;这也说明了memcache不适合做数据库来用,可以用来做缓存。

引言

这里我们主要利用Redis的setnx的命令来处理高并发。

setnx 有两个参数。第一个参数表示键。第二个参数表示值。如果当前键不存在,那么会插入当前键,将第二个参数做为值。返回 1。如果当前键存在,那么会返回0。

创建库存表

CREATETABLE`storage`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`number`int(11)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=latin1

设置初始库存为10

创建订单表

CREATETABLE`order`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`number`int(11)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=latin1

测试不用锁的时候

$pdo=newPDO('mysql:host=127.0.0.1;dbname=test','root','root');$sql="select`number`fromstoragewhereid=1limit1";$res=$pdo->query($sql)->fetch();$number=$res['number'];if($number>0){$sql="insertinto`order`VALUES(null,$number)";$order_id=$pdo->query($sql);if($order_id){$sql="updatestorageset`number`=`number`-1WHEREid=1";$pdo->query($sql);}}

ab测试模拟并发,发现库存是正确的。

mysql>select*fromstorage;+----+--------+|id|number|+----+--------+|1|0|+----+--------+1rowinset(0.00sec)

在来看订单表

mysql>select*from`order`;+----+--------+|id|number|+----+--------+|1|10||2|10||3|9||4|7||5|6||6|5||7|5||8|5||9|4||10|1|+----+--------+10rowsinset(0.00sec)

发现存在几个订单都是操作的同一个库存数据,这样就可能引起超卖的情况。

修改代码加入redis锁进行数据控制

<?php/***CreatedbyPhpStorm.*User:daisc*Date:2018/7/23*Time:14:45*/classLock{privatestatic$_instance;private$_redis;privatefunction__construct(){$this->_redis=newRedis();$this->_redis->connect('127.0.0.1');}publicstaticfunctiongetInstance(){if(self::$_instanceinstanceofself){returnself::$_instance;}returnself::$_instance=newself();}/***@function加锁*@param$key锁名称*@param$expTime过期时间*/publicfunctionset($key,$expTime){//初步加锁$isLock=$this->_redis->setnx($key,time()+$expTime);if($isLock){returntrue;}else{//加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁$val=$this->_redis->get($key);if($val&&$val<time()){$this->del($key);}return$this->_redis->setnx($key,time()+$expTime);}}/***@param$key解锁*/publicfunctiondel($key){$this->_redis->del($key);}}$pdo=newPDO('mysql:host=127.0.0.1;dbname=test','root','root');$lockObj=Lock::getInstance();//判断是能加锁成功if($lock=$lockObj->set('storage',10)){$sql="select`number`fromstoragewhereid=1limit1";$res=$pdo->query($sql)->fetch();$number=$res['number'];if($number>0){$sql="insertinto`order`VALUES(null,$number)";$order_id=$pdo->query($sql);if($order_id){$sql="updatestorageset`number`=`number`-1WHEREid=1";$pdo->query($sql);}}//解锁$lockObj->del('storage');}else{//加锁不成功执行其他操作。}

再次进行ab测试,查看测试结果

mysql>select*from`order`;+----+--------+|id|number|+----+--------+|1|10||2|9||3|8||4|7||5|6||6|5||7|4||8|3||9|2||10|1|+----+--------+10rowsinset(0.00sec)

发现订单表没有操作同一个库存数据的情况。所以利用redis锁是可以有效的处理高并发的。

这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。

看完了这篇文章,相信你对“怎么利用Redis锁解决高并发”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!