共计 3296 个字符,预计需要花费 9 分钟才能阅读完成。
自动写代码机器人,免费开通
丸趣 TV 小编给大家分享一下怎么利用 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);
}
}
$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 锁是可以有效的处理高并发的。
这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。
看完了这篇文章,相信你对“怎么利用 Redis 锁解决高并发”有了一定的了解,如果想了解更多相关知识,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!
向 AI 问一下细节