温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么利用Redis锁解决高并发

发布时间:2021-02-08 09:54:58 来源:亿速云 阅读:158 作者:小新 栏目:数据库

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

redis技术的使用:

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

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

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

引言

这里我们主要利用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锁是可以有效的处理高并发的。

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

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI