您好,欢迎访问一九零五行业门户网

如何利用Redis锁解决高并发问题

高并发问题是我们经常可以遇到的问题,那么该如何解决高并发这个问题呢?本篇文章介绍的内容就是利用redis锁解决高并发问题,一起来看看吧。
这里我们主要利用redis的setnx的命令来处理高并发。
setnx 有两个参数。第一个参数表示键。第二个参数表示值。如果当前键不存在,那么会插入当前键,将第二个参数做为值。返回 1。如果当前键存在,那么会返回0。
创建库存表
create table `storage` (  `id` int(11) unsigned not null auto_increment,  `number` int(11) default null,  primary key (`id`)) engine=innodb auto_increment=1 default charset=latin1
设置初始库存为10
创建订单表
create table `order` (  `id` int(11) unsigned not null auto_increment,  `number` int(11) default null,  primary key (`id`)) engine=innodb auto_increment=1 default charset=latin1
测试不用锁的时候
$pdo = new pdo('mysql:host=127.0.0.1;dbname=test', 'root', 'root');$sql=select `number` from  storage where id=1 limit 1;$res = $pdo->query($sql)->fetch();$number = $res['number'];if($number>0){    $sql =insert into `order`  values (null,$number);    $order_id = $pdo->query($sql);    if($order_id)    {        $sql=update storage set `number`=`number`-1 where id=1;        $pdo->query($sql);    }}
ab测试模拟并发,发现库存是正确的。
mysql> select * from storage;+----+--------+| id | number |+----+--------+|  1 |      0 |+----+--------+1 row in set (0.00 sec)
在来看订单表
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 |+----+--------+10 rows in set (0.00 sec)
发现存在几个订单都是操作的同一个库存数据,这样就可能引起超卖的情况。
修改代码加入redis锁进行数据控制
<?php/** * created by phpstorm. * user: daisc * date: 2018/7/23 * time: 14:45 */class lock{ private static $_instance ; private $_redis; private function __construct() { $this->_redis =  new redis();        $this->_redis ->connect('127.0.0.1');    }    public static function getinstance()    {        if(self::$_instance instanceof self)        {            return self::$_instance;        }        return self::$_instance = new  self();    }    /**     * @function 加锁     * @param $key 锁名称     * @param $exptime 过期时间      */    public function set($key,$exptime)    {        //初步加锁        $islock = $this->_redis->setnx($key,time()+$exptime);        if($islock)        {            return true;        }        else        {            //加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁            $val = $this->_redis->get($key);            if($val&&$val<time()) { $this->del($key);            }            return  $this->_redis->setnx($key,time()+$exptime);        }    }    /**     * @param $key 解锁     */    public function del($key)    {        $this->_redis->del($key);    }}$pdo = new pdo('mysql:host=127.0.0.1;dbname=test', 'root', 'root');$lockobj = lock::getinstance();//判断是能加锁成功if($lock = $lockobj->set('storage',10)){    $sql=select `number` from  storage where id=1 limit 1;    $res = $pdo->query($sql)->fetch();    $number = $res['number'];    if($number>0)    {        $sql =insert into `order`  values (null,$number);        $order_id = $pdo->query($sql);        if($order_id)        {            $sql=update storage set `number`=`number`-1 where id=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 |+----+--------+10 rows in set (0.00 sec)
发现订单表没有操作同一个库存数据的情况。所以利用redis锁是可以有效的处理高并发的。
这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。
相关推荐:
php利用文件锁来解决高并发问题
使用redis来存储php的session如何解决并发一致性的问题
以上就是如何利用redis锁解决高并发问题的详细内容。
其它类似信息

推荐信息