Слияние кода завершено, страница обновится автоматически
<?php
namespace buwang\service;
/**
* Class RedisLockService
* @package buwang\service
*/
class RedisLockService
{
private $lockKey; //锁的键名
private $Timeout; //超时时间
private $redis; //$reids实例
private $Negtive = true; //是否是悲观锁
private $identify = ""; //锁的唯一标识,防止锁被别的进程误删
//redis 配置
private $redisConfig = [
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'AUTH',
'select' => 0,
'timeout' => 0,
'expire' => 0,
'persistent' => false,
'prefix' => '',
];
/**
* RedisDistributedLock constructor.
* @param $lockKey
* @param array $config
* @param int $aTimeout
* @param bool $Negtive
* @throws RedisException
* @throws \RedisException
* @throws \Exception
*/
public function __construct($lockKey,$config=[], $aTimeout = 5, $Negtive = true)
{
if (!extension_loaded('redis')) {
throw new \BadFunctionCallException('不支持: redis');
}
if (!$lockKey) {
throw new \Exception("lockKey不能为空");
}
//合并redis配置
if (!empty($config)){
$this->redisConfig = array_merge($this->redisConfig, $config);
}
try {
$this->lockKey = $lockKey; //锁的键名
$this->Negtive = $Negtive; //是否是悲观锁,是
$this->Timeout = $aTimeout; //超时
$this->redis = new \Redis(); //实例redis
//是否保持连接
if ($this->redisConfig['persistent']) {
$this->redis->pconnect($this->redisConfig['host'], $this->redisConfig['port'], $this->redisConfig['timeout'], 'persistent_id_' . $this->redisConfig['select']);
} else {
$this->redis->connect($this->redisConfig['host'], $this->redisConfig['port'], $this->redisConfig['timeout']);
}
$this->redisConfig['password'] && $this->redis->auth($this->redisConfig['password']);
// 赋值全局,避免多次实例化
$GLOBALS['SPREDIS'] = $this->redis;
} catch (\RedisException $e) {
throw $e;
}catch (\Exception $exception){
throw new \Exception($exception->getMessage());
}
}
/**
* @return \Redis
* @author: bwsaas <hnlg666@163.com>
* @describe:获取实例
*/
public function getRedis() {
return $this->redis;
}
/**
* @return bool
* @author: bwsaas <hnlg666@163.com>
* @describe:获取锁
*/
public function getLock()
{
$v = uniqid();
if ($this->Negtive) {
//悲观锁
$endtime = microtime(true) * 1000 + $this->Timeout * 1000;
while (microtime(true) * 1000 < $endtime) {
//每隔一段时间尝试获取一次锁
$acquired = $this->redis->set($this->lockKey, $v, ["NX", "EX" => $this->Timeout]);
if ($acquired) {
//获取锁成功
$this->identify = $v;
return true;
}
usleep(100);
}
//获取锁超时
return false;
} else {
//乐观锁
//乐观锁只尝试一次,成功返回true,失败返回false
$acquired = $this->redis->set($this->lockKey, $v, ["NX", "EX" => $this->Timeout]);
if ($acquired) {
$this->identify = $v;
return true;
}
return false;
}
}
/**
* @return bool
* @author: bwsaas <hnlg666@163.com>
* @describe:释放锁
*/
public function unLock()
{
//如果没有成功获得锁,直接返回false
if (!$this->identify) {
return false;
}
//由于判断是否相等和删除是两步操作,因此使用 lua 脚本来保证原子性
$script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
$result = $this->redis->eval($script, [$this->lockKey, $this->identify], 1);
if ($result) {
return true;
}
return false;
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )