65 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			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);
 | |
|     }
 | |
| } |