框架Yii2 1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功。
例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制的情况下,用户则可以使用同一个换领码同时兑换到多张优惠券。 伪代码如下:
代码语言:javascript复制if A(可以换领)
B(执行换领)
C(更新为已换领)
D(结束)
如果用户并发提交换领码,都能通过可以换领(A)的判断,因为必须有一个执行换领(B)后,才会更新为已换领(C)。
因此如果用户在有一个更新为已换领之前,有多少次请求,这些请求都可以执行成功。?
代码语言:javascript复制<?php
/**
* Created by ZhengNiu.
* User: 77103
* Date: 2019/3/28
* Time: 9:38
*/
namespace apphelper;
use Yii;
class RedisLock
{
private $_redis;
private $key;
private $expire;
/**
* 初始化redis
*
* RedisLock constructor.
* @param string $key 锁标识
* @param int $expire 锁过期时间
*/
public function __construct($key, $expire = 5)
{
try{
$this->_redis = Yii::$app->redis;
$this->key = $key;
$this->expire = $expire;
}catch (Exception $ex) {
return new Exception($ex->getMessage());
}
}
/**
* 获取锁
*
* @return bool
*/
public function lock()
{
//不存在则返回1,存在返回0
$is_lock = $this->_redis->setnx($this->key, time() $this->expire);
// 不能获取锁
if (!$is_lock) {
// 判断锁是否过期
$lock_time = $this->_redis->get($this->key);
// 锁已过期,删除锁,重新获取
if (time() > $lock_time) {
$this->unlock($this->key);
$is_lock = $this->_redis->setnx($this->key, time() $this->expire);
}
}
return $is_lock ? true : false;
}
/**
* 释放锁
*
* @return Boolean
*/
public function unlock()
{
return $this->_redis->del($this->key);
}
}
调用:
<?php
/**
* 锁机制
*/
public function actionLock()
{
$this->layout = false;
$oRedisLock = new RedisLock('test2', 10);// 创建redislock对象
$is_lock = $oRedisLock->lock();
if ($is_lock) {
echo 'get lock success</br>';
//业务逻辑start
sleep(5);
//业务逻辑end
$oRedisLock->unlock();
} else {
echo 'request too frequently</br>';
}
}
测试结果:打开两个浏览器 先访问的浏览器
get lock success
do sth..
success
后者:
request too frequently