<?php
/**
* Created by PhpStorm.
* User: chelun
* Date: 2018/12/26
* Time: 下午8:15
*/
namespace App\Util;
use Illuminate\Support\Facades\Redis;
class RedisLock
{
const LOCK_KEY = 'WRB_LOCK:';
/**
* @param string $redisInst
* @return redis
*/
public static function getRedis($redisInst = 'default')
{
return Redis::connection($redisInst);
}
/**
* @param string $lockKey
* @return bool
*/
public static function lock($lockKey = '', $expire = 5, $forceLock = true)
{
$oriKey = $lockKey;
$lockKey = self::LOCK_KEY.$oriKey;
$redis = self::getRedis();
$isLock = $redis->setnx($lockKey, time() + $expire);
if(!$isLock)
{
$lockTime = $redis->get($lockKey);
if(time() >= $lockTime)
{
self::unlock($oriKey);
if($forceLock)
{
$isLock = $redis->setnx($lockKey, time() + $expire);
}
else
{
return true;
}
}
}
return $isLock ? true : false;
}
/**
* @param $lockKey
* @return bool
*/
public static function unlock($lockKey)
{
$lockKey = self::LOCK_KEY.$lockKey;
$redis = self::getRedis();
$redis->del($lockKey);
return true;
}
}
<?php
/**
* Created by PhpStorm.
* User: chelun
* Date: 2019/9/27
* Time: 上午9:53
*/
namespace App\Common;
class CacheLock
{
private $_cache = null;
private $_key = '';
private $_expire = 30;
private $_isInstance = false;
private $_isLocked = false;
private $_autoUnLock = true;
public function __construct($key)
{
if (empty($key))
{
throw new \Exception('new CacheLock($key) $key is not empty');
}
$this->_cache = app('redis');
$this->_key = $this->cacheKey(__FILE__, $key);
$this->_expire = ini_get('max_execution_time') > 0 ? ini_get('max_execution_time') : 30;
}
/**
* 设定缓存的强制锁定时间,必须锁定足够时间才能解锁
* @param int|number $sec
* @throws Exception
*/
public function setExpire($sec = 5)
{
$this->_autoUnLock = false;
$this->_expire = $sec;
if ($sec > 86400)
{
throw new \Exception('$sec is too large,more than 1 day');
}
}
/**
* 采用CAS乐观锁
*
* @throws Exception
* @return boolean
*/
public function lock()
{
if ($this->_isInstance)
{
throw new \Exception('每个CacheLock实例只能lock一次,当一个请求中需要多次锁定时,请分别实例化CacheLock类');
}
try
{
$this->_isLocked = true;
$this->_isInstance = true;
if ($this->_cache->exists($this->_key))
{
return $this->_isLocked;
}
$this->_cache->watch($this->_key);
$val = $this->_cache->get($this->_key);
if ($val !== false)
{
return $this->_isLocked;
}
$rst = $this->_cache->multi()
->incr($this->_key)
->expireAt($this->_key, time() + $this->_expire)
->exec();
if ($rst !== false)
{
$this->_isLocked = false;
}
return $this->_isLocked;
}
catch (\Exception $e)
{
return true;
}
}
/**
* 返回ttl信息
*
*/
public function ttl()
{
return $this->_cache->ttl($this->_key);
}
/**
* 释放锁,在特定情况下,手动释放
* @return bool
* @throws Exception
*/
public function release()
{
if (!$this->_cache instanceof redis)
{
throw new \Exception('$this->_cache is not a redis instance');
}
$this->_cache->delete($this->_key);
return true;
}
function cacheKey()
{
$args = func_get_args();
return md5(__FILE__ . serialize($args));
}
/**
* 自动释放锁,注意点:只有加锁的人自己才可以解锁
*/
public function __destruct()
{
if (!$this->_isLocked && $this->_autoUnLock)
{
$this->_cache->delete($this->_key);
$this->_cache->close();
}
}
}