1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/buwangyun-bwsaas

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
RedisLockService.php 4.2 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
hnlg666 Отправлено 4 лет назад ef29068
<?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 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/buwangyun-bwsaas.git
git@gitlife.ru:oschina-mirror/buwangyun-bwsaas.git
oschina-mirror
buwangyun-bwsaas
buwangyun-bwsaas
v1.3.2