redis锁


  需要的知识点:

SET

SET key value [EX seconds] [PX milliseconds] [NX|XX] 将字符串值 value 关联到 key 。 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。 可选参数 从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
    • EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
    • PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
    • NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
    • XX :只在键已经存在时,才对键进行设置操作。
* <pre>
* // Simple key -> value set
* $redis->set('key', 'value');
*
* // Will redirect, and actually make an SETEX call
* $redis->set('key','value', 10);
*
* // Will set the key, if it doesn't exist, with a ttl of 10 seconds
* $redis->set('key', 'value', ['nx', 'ex' => 10]);
*
* // Will set a key, if it does exist, with a ttl of 1000 milliseconds
* $redis->set('key', 'value', ['xx', 'px' => 1000]);
* </pre>
  在thinkphp框架 缓存cache 默认是没有setNx功能的,所以需要自己增加扩展。如下代码
/**
 * 扩展thinkRedis类,支持更多redis操作.
 */
class Redis extends \think\cache\driver\Redis
{
    public function setNx($key, $value, $expireIn = null)
    {
        return $this->handler->set($key, $value, ['NX', 'EX' => $expireIn]);
    }
}

实现

class RedisLock
{
    private $key;
    private $redis;

    public function __construct()
    {
        $this->redis = new Redis();
    }

    /**
     * 加锁
     *
     * @param $key
     *
     * @return bool 成功新加锁 true,锁已存在返回false
     */
    public function lock($key, int $expireIn = 5, int $wait = 0)
    {
        $this->key = $this->getKey($key);

        do {
            $lock = $this->redis->setNx($this->key, time(), $expireIn);
            if ($lock) {
                return true;
            }
            if ($wait > 0) {
                sleep(1);
            }
        } while ($wait--); //防止偶尔性的获取锁失败的情况
        //无法正常获取锁 不允许往下进行
        return false;
    }

    /**
     * 释放锁
     *
     * @return bool
     */
    public function unlock()
    {
        return $this->redis->delete($this->key);
    }

    private function getKey($key)
    {
        $keyPrefix = config('keys.redis_lock_key', 'redis_lock_key_prefix');

        return sprintf('%s_%s', $keyPrefix, $key);
    }
}
公共函数
if (!function_exists('redis_lock')) {
    /**
     * redis 锁
     *
     * @param $key
     * @param $value
     * @param $expireIn
     * @param $wait
     *
     * @throws \think\Exception
     *
     * @return mixed
     */
    function redis_lock($key, $value, $expireIn = 5, $wait = 0)
    {
        /** @var RedisLock $redisLock */
        $redisLock = app(RedisLock::class);

        if (!$redisLock->lock($key, $expireIn, $wait)) {
            throw new \think\Exception(config('error_code.redis_lock_exception'));
        }

        try {
            if ($value instanceof Closure) {
                $value = Container::getInstance()->invokeFunction($value);
            }
        } finally {
            $redisLock->unlock();
        }

        return $value;
    }
}
        发布时间 : 2023-02-28,阅读量:1077
本文链接:https://upwqy.com/details/48.html
阿里云负载均衡-宝塔多站点 phpstudy安装报错