redis锁
需要的知识点:
SET
SET key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值
value 关联到
key 。
如果
key 已经持有其他值, SET 就覆写旧值,无视类型。
对于某个原本带有生存时间(TTL)的键来说, 当
SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
可选参数
从 Redis 2.6.12 版本开始,
SET 命令的行为可以通过一系列参数来修改:
-
- EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
- PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
- NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
- XX :只在键已经存在时,才对键进行设置操作。
* <pre>
* // Simple key -> value set
* $redis->set('key', 'value');
*
* // Will redirect, and actually make an SETEX call
* $redis->set('key','value', 10);
*
* // Will set the key, if it doesn't exist, with a ttl of 10 seconds
* $redis->set('key', 'value', ['nx', 'ex' => 10]);
*
* // Will set a key, if it does exist, with a ttl of 1000 milliseconds
* $redis->set('key', 'value', ['xx', 'px' => 1000]);
* </pre>
在thinkphp框架 缓存cache 默认是没有setNx功能的,所以需要自己增加扩展。如下代码
/**
* 扩展thinkRedis类,支持更多redis操作.
*/
class Redis extends \think\cache\driver\Redis
{
public function setNx($key, $value, $expireIn = null)
{
return $this->handler->set($key, $value, ['NX', 'EX' => $expireIn]);
}
}
实现
class RedisLock
{
private $key;
private $redis;
public function __construct()
{
$this->redis = new Redis();
}
/**
* 加锁
*
* @param $key
*
* @return bool 成功新加锁 true,锁已存在返回false
*/
public function lock($key, int $expireIn = 5, int $wait = 0)
{
$this->key = $this->getKey($key);
do {
$lock = $this->redis->setNx($this->key, time(), $expireIn);
if ($lock) {
return true;
}
if ($wait > 0) {
sleep(1);
}
} while ($wait--); //防止偶尔性的获取锁失败的情况
//无法正常获取锁 不允许往下进行
return false;
}
/**
* 释放锁
*
* @return bool
*/
public function unlock()
{
return $this->redis->delete($this->key);
}
private function getKey($key)
{
$keyPrefix = config('keys.redis_lock_key', 'redis_lock_key_prefix');
return sprintf('%s_%s', $keyPrefix, $key);
}
}
公共函数
if (!function_exists('redis_lock')) {
/**
* redis 锁
*
* @param $key
* @param $value
* @param $expireIn
* @param $wait
*
* @throws \think\Exception
*
* @return mixed
*/
function redis_lock($key, $value, $expireIn = 5, $wait = 0)
{
/** @var RedisLock $redisLock */
$redisLock = app(RedisLock::class);
if (!$redisLock->lock($key, $expireIn, $wait)) {
throw new \think\Exception(config('error_code.redis_lock_exception'));
}
try {
if ($value instanceof Closure) {
$value = Container::getInstance()->invokeFunction($value);
}
} finally {
$redisLock->unlock();
}
return $value;
}
}
发布时间 : 2023-02-28,阅读量:1077
本文链接:
https://upwqy.com/details/48.html