cmbYouku_Api/app/service/util/DistributedLockService.php

65 lines
1.7 KiB
PHP

<?php
declare (strict_types=1);
namespace app\service\util;
use app\exception\BusinessException;
use Predis\Client;
/**
* @author canny
* @date 2023/10/26 9:59
**/
class DistributedLockService
{
protected Client $redis;
protected string $lockKey;
protected string $lockValue;
protected $lockTimeout;
public function __construct($lockKey, $lockTimeout = 10)
{
$this->redis = RedisService::getRedisInstance();
$this->lockKey = $lockKey;
$this->lockValue = uniqid(); // 生成一个唯一的值作为锁的值
$this->lockTimeout = $lockTimeout;
}
/**
* @throws BusinessException
*/
public function acquireLock($callback)
{
$result = $this->redis->set($this->lockKey, $this->lockValue, 'ex', $this->lockTimeout, 'nx');
if (empty($result) || $result->getPayload() !== 'OK') {
throw new BusinessException("处理中,请稍后再试");
}
try {
return $callback();
}catch (\Throwable $throwable){
throw new BusinessException($throwable->getMessage(), $throwable->getCode());
} finally {
$this->releaseLock();
}
}
private function releaseLock()
{
// 释放锁,只有锁的值匹配时才会删除锁,以避免误释放
$script = "
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
";
$this->redis->eval($script, 1, $this->lockKey, $this->lockValue);
}
public function renewLock()
{
// 续期锁的过期时间
$this->redis->expire($this->lockKey, $this->lockTimeout);
}
}