这里我们主要利用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:45html' target='_blank'>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);
$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 //加锁不成功执行其他操作。}
再次进行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锁解决高并发问题的详细内容,PHP教程
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
新闻热点
疑难解答