redis内存锁类库

lys2019年10月22日 0条评论

Redis内存锁,这边使用Yii2.0框架

具体查看如下:

<?php
namespace common\components;
/**
 * redis锁服务类
 * User: linyushan
 * Date: 2019/9/12
 * Time: 16:30
 */
class RedisLockService{

    /**
     * Redis内存锁
     * @author linyushan
     * @date 2018/10/17 16:00:00
     * @param  string  $key    锁标识
     * @param  Int     $expire 锁过期时间
     * @return Boolean  锁定成功返回true 如果已被锁住则返回 false
     */
    public static function lock($key, $expire = 60){
        /**
         * @var \yii\redis\Connection $redis
         */
        $redis = \Yii::$app->redis;
        $redis->multi();
        $is_lock = $redis->setnx($key, time()+$expire);
        $is_lock && $redis->expire($key,$expire);  //设置超时时间
        $redis->exec();
        return $is_lock ? true : false;
    }

    /**
     * Redis 解锁
     * @author linyushan
     * @date 2018/10/17 16:00:00
     * @param  string  $key    锁标识
     * @return Boolean  锁定成功返回true 如果已被锁住则返回 false
     */
    public static function unLock($key){
        return self::del($key);
    }

    /**
     * 删除
     * @param $key
     * @return mixed
     */
    public static function del($key){
        /**
         * @var \yii\redis\Connection $redis
         */
        $redis = \Yii::$app->redis;
        return $redis->del($key);
    }

    /**
     * 判断是否要过期,继续添加时间
     * @param string $key  //锁key
     * @param int $time  //单位秒  剩余时间小于这个值,需要重新设置时间
     * @param int $value  //单位秒  需要设置的时间
     */
    public static function checkTimeOutAddExpire($key,$time,$value){
        /**
         * @var \yii\redis\Connection $redis
         */
        $redis = \Yii::$app->redis;
        if($redis->ttl($key) < $time){
            $redis->expire($key,$value);
        }
    }

    /**
     * 闭包redis锁
     * @param callable $callback //闭包回调函数
     * @param string $key //锁名
     * @param int $expire //锁定时间(单位 秒)
     * @param callable $lockCallBackFunc  //并发锁定回调函数
     * @return boolean
     */
    public static function begin(callable $callback,$key = '', $expire = 10,$lockCallBackFunc = null){
        if(empty($key)){
            return false;
        }
        if(!self::lock($key,$expire)){  //加锁
            if(!empty($lockCallBackFunc)
                && is_callable($lockCallBackFunc)){
                return $lockCallBackFunc();
            }
            return false;
        }
        $result = $callback();
        self::unLock($key); //解锁
        return $result;
    }

    /**
     * 进程排他,设定一个key在该进程未结束的时候,排斥同一个锁的进程执行
     * @author lys
     * @date 2019/09/24 09:26:00
     * @param string $lockKey  //锁名称key
     * @return boolean
     */
    public static function lockProcess($lockKey = '',$lockTime = 60){
        if(empty($lockKey)){
            return false;
        }
        if(!self::lock($lockKey,$lockTime)){
            return false;
        }
        register_shutdown_function(function () use ($lockKey){  //注册进程结束需要处理的事情
             self::unLock($lockKey);  //解锁
        });
        return true;
    }


    /**
     * 唯一id生成锁定,防止并发
     * @param string $prefix  //锁前缀
     * @param callable $func  //匿名函数闭包
     * @param int $timeout  //锁定时间(单位秒)
     * @return bool|string|int
     */
    public static function LockGetUniqid($prefix, callable $func, $timeout = 10){
        if(empty($prefix)){
            return false;
        }
        while (1){
            $str = $func();  //生成随机字符串或者数字
            if(empty($str)){
                return false;
            }
            if(!self::lock($prefix.':'.$str, $timeout)){
                usleep(10);
                continue;
            }
            return $str;
        }
        return false;
    }
}