PHP Redis鎖

1、什麼是 Redis

Redis是由意大利人Salvatore Sanfilippo(網名:antirez)開發的一款內存高速緩存數據庫php

2、什麼是 Redis 分佈式鎖

分佈式鎖其實能夠理解爲:控制分佈式系統有序的去對共享資源進行操做,經過互斥來保持一致性。 舉個不太恰當的例子:假設共享的資源就是一個房子,裏面有各類書,分佈式系統就是要進屋看書的人,分佈式鎖就是保證這個房子只有一個門而且一次只有一我的能夠進,並且門只有一把鑰匙。而後許多人要去看書,能夠,排隊,第一我的拿着鑰匙把門打開進屋看書而且把門鎖上,而後第二我的沒有鑰匙,那就等着,等第一個出來,而後你在拿着鑰匙進去,而後就是以此類推redis

3、Redis 鎖使用場景

  1. 數據高併發的讀寫數據庫

  2. 海量數據的讀寫json

  3. 對擴展性要求高的數據數組

4、代碼實現

基於Yii 1.2緩存

<?php
namespace commons\base;
use Redis;

/**
 *  Redis鎖操做類,防止併發訪問
 */
class RedisLock
{
    private static $_instance = null;

    /**
     * @var Redis
     */
    private $_redis;

    //key前綴
    private $_lockPrefix = "common_base_lock:";

    public function __construct()
    {
        $this->_redis = Redis::getInstance();
    }

    public static function getInstance()
    {
        if(self::$_instance == null)
        {
            self::$_instance = new RedisLock();
        }
        return self::$_instance;
    }

    /**
     * 加鎖
     * @param string $key      -加鎖的key
     * @param int $wait        -鎖等待時間,秒
     * @param int $expire      -鎖失效時間,秒
     * @return boolean
     * 獲取鎖成功返回
     */
    public function lock($key,$wait=1,$expire=5)
    {
        $hasWait = 0;//已經等待的時間:毫秒
        do
        {
            $getLock = $this->_redis->setNx($this->_getKeyName($key),1,$expire);//經過setNx獲取鎖,只有一個能拿到
            if(!$getLock)//沒拿到鎖
            {
                if($hasWait > $wait*1000)//等待超時
                {
                    return false;
                }
                usleep(30000);//等待30ms
                $hasWait += 30;
                continue;
            }
            return true;
        }
        while(true);
    }

    /**
     * 加鎖, 非阻塞, 獲取鎖失敗或者成功直接返回
     * @param string $key      -加鎖的key
     * @param int $expire      -鎖失效時間,秒
     * @return boolean
     * 獲取鎖成功返回
     */
    public function NBLock($key, $expire=5)
    {
        return  $this->_redis->setNx($this->_getKeyName($key),1,$expire);//經過setNx獲取鎖,只有一個能拿到
    }

    /**
     * 釋放鎖
     * @param string $key    -鎖的key
     * @return boolean
     */
    public function unlock($key)
    {
        return $this->_redis->delete($this->_getKeyName($key));
    }

    private function _getKeyName($key)
    {
        return $this->_lockPrefix . $key;
    }
}

 

<?php
namespace datalevels;
use base\Config;
use base\Logger;

/**
 * redis
 * 兼容yii cache接口,可使用\Yii::app()->cache->get() 形式使用
 * 也可使用: Redis::getInstance()->get() 形式使用
 * 推薦使用Redis::getInstance()形式,\Yii::app()->cache只是爲了兼容YII框架處理,redis接口遠比yii框架的cache接口豐富。
 */
class Redis extends \CCache
{
    /**
     * 無窮大
     * @var string
     */
    const  MAX_VALUE = '+inf';

    /**
     * 無窮小
     * @var string
     */
    const  MIN_VALUE = '-inf';

    /**
     * 聚合類型,求和
     * @var string
     */
    const AGGREGATE_TYPE_SUM = 'SUM';

    /**
     * 聚合類型,最大值
     * @var string
     */
    const AGGREGATE_TYPE_MAX = 'MAX';

    /**
     * 聚合類型,最小值
     * @var string
     */
    const AGGREGATE_TYPE_MIN = 'MIN';

    /**
     * redis
     * @var Redis
     */
    private static $_instance = null;

    /**
     * redis連接
     * @var \Redis
     */
    private $_redis = null;

    private $_conf = array();

    public function __construct()
    {
        $this->_conf = Config::getInstance()->get("", 'redis');
        if (empty($this->_conf) || !isset($this->_conf['host']) || !isset($this->_conf['port'])) {
            throw new DaoException("redis config invalid.");
        }
        try{
            if (!$this->_connect()) {
                throw new DaoException("connect to redis failure");
            }
        } catch (\RedisException $e) {
            Logger::error("connect to redis failure.");
            throw new DaoException("connect to redis failure");
        }
    }

    /**
     * 獲取redis實例
     * @return Redis
     */
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new Redis();
        }
        return self::$_instance;
    }
/**
     * Get the value related to the specified key
     * @param string $key
     * @return String or Bool: If key didn't exist, FALSE is returned. Otherwise, the value related to this key is returned.
     */
    public function get($key)
    {
        return $this->_redis->get($key);
    }


    /**
     * Get the values of all the specified keys. If one or more keys dont exist, the array will contain FALSE at the position of the key.
     * @param array $keys       - key數組
     * @return Array: Array containing the values related to keys in argument
     */
    public function mget($keys)
    {
        return $this->_redis->mget($keys);
    }

    /**
     * Set the string value in argument as value of the key
     * @param string $key
     * @param mixed $value        -   任意值
     * @param int $expire         -   過時時間,單位秒
     * @return bool 成功返回true
     */
    public function set($key, $value, $expire = 0, $dependency = null)
    {
        if ($expire > 0) {
            return $this->_redis->set($key, $value, $expire);
        }
        return $this->_redis->set($key, $value);
    }

    /**
     * 設置key值,若是key存在則失敗
     * @param string $key
     * @param mixed $value        -   任意值
     * @param int $expire         -   過時時間,單位秒
     * @return bool 成功返回true, key存在返回false
     */
    public function setNx($key, $value, $expire = 0)
    {
        $ret = $this->_redis->setNx($key, $value);
        if (true === $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * Verify if the specified key exists.
     * @param string $key
     * @return BOOL: If the key exists, return TRUE, otherwise return FALSE.
     */
    public function exists($key)
    {
        return $this->_redis->exists($key);
    }

    /**
     * Sets a value and returns the previous entry at that key.
     * @param string $key
     * @param mixed $value        -   任意值
     * @param int $expire         -   過時時間,單位秒
     */
    public function getSet($key, $value, $expire = 0)
    {
        $prev = $this->_redis->getSet($key, $value);
        if ($expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $prev;
    }

    /**
     *  增長key 的值
     * @param string $key
     * @param number $step      - 增長步長,每次加多少
     * @param int $expire            - 超時時間
     * @return int   最新值
     */
    public function incr($key, $step = 1, $expire = 0)
    {
        $ret = false;
        if ($step > 1) {
            $ret =  $this->_redis->incrBy($key, $step);
        }
        else {
            $ret = $this->_redis->incr($key);
        }

        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     *  減小key 的值
     * @param string $key
     * @param number $step      - 減小步長,每次減多少
     * @param int $expire            - 超時時間
     * @return int   最新值
     */
    public function decr($key, $step = 1, $expire = 0)
    {
        $ret = false;
        if ($step > 1) {
            $ret =  $this->_redis->decrBy($key, $step);
        }
        else {
            $ret = $this->_redis->decr($key);
        }

        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }



    /**
     * Remove specified keys.
     * @param string $key           - 批量刪除,傳遞key數組
     * @return mixed - Long Number of keys deleted.
     */
    public function delete($key)
    {
        return $this->_redis->delete($key);
    }

    /**
     * 重命名key
     * @param $srcKey       - 原key
     * @param $dstKey       - 更名後的key
     * @return bool     - 成功返回true
     */
    public function rename($srcKey, $dstKey)
    {
        return $this->_redis->rename($srcKey, $dstKey);
    }

    /**
     * 設置key超時時間,單位秒
     * @param string $key            - 設置key超時時間
     * @param int $expire            - 不限制設置-1
     * @return bool 成功返回true
     */
    public function setTimeout($key, $expire)
    {
        return $this->_redis->setTimeout($key, $expire);
    }

    /**
     * 獲取該key在redis裏的剩餘存活時間,單位秒
     * @param string $key     -key
     * @return int|false      -成功返回時間
     */
    public function ttl($key)
    {
        $restTime=$this->_redis->ttl($key);
        if($restTime>=0)
        {
            return $restTime;
        }
        else
        {
            return false;
        }
    }

    /**
     * hash表操做 - 刪除hash字段
     * @param string  $key
     * @param string $field  - hash字段
     * @return LONG the number of deleted keys, 0 if the key doesn't exist, FALSE if the key isn't a hash.
     */
    public function hDel($key, $field)
    {
        return $this->_redis->hDel($key, $field);
    }

    /**
     * hash表操做 - 檢測hash 字段是否存在
     * @param string  $key
     * @param string $field   - hash字段
     * @return BOOL: If the member exists in the hash table, return TRUE, otherwise return FALSE.
     */
    public function hExists($key, $field)
    {
        return $this->_redis->hExists($key, $field);
    }

    /**
     * hash表操做 - 獲取hash字段的值
     * @param string  $key
     * @param string $field    - 字段
     * @return mixed | false    - 成功返回值,失敗返回false
     */
    public function hGet($key, $field)
    {
        return json_decode($this->_redis->hGet($key, $field), true);
    }

    /**
     * hash表操做 - 獲取hash表中全部字段值
     * @param string  $key
     * @return array
     */
    public function hGetAll($key)
    {
        return $this->_redis->hGetAll($key);
    }

    /**
     * hash表操做 - 增長hash字段的數值
     * @param string  $key
     * @param string $field   - hash字段
     * @param number $step      - 增長步長,每次加多少
     * @param int $expire            - 超時時間
     * @return LONG 返回新值
     */
    public function hIncrBy($key, $field, $step = 1, $expire = 0)
    {
        $ret = $this->_redis->hIncrBy($key, $field, $step);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * hash表操做 - 返回所有hash字段
     * @param string $key
     * @return array
     */
    public function hKeys($key)
    {
        return $this->_redis->hKeys($key);
    }

    /**
     * hash表操做 - 返回hash的字段數
     * @param string $key
     * @return int key不存在返回false
     */
    public function hLen($key)
    {
        return $this->_redis->hLen($key);
    }

    /**
     * hash表操做 - 批量獲取hash的字段值
     * @param string $key
     * @param array $fields       -    hash字段
     * @return boolean|mixed
     */
    public function hMGet($key, array $fields)
    {
        if (empty($fields)) {
            return false;
        }
        return $this->_redis->hMget($key, $fields);
    }

    /**
     * hash表操做 - 批量設置hash字段值
     * @param string $key
     * @param array $fields         -   hash字段數組, 例:array('uid' => 1, 'name' => 'lewaimai')
     * @param int $expire             -   過時時間,單位秒
     * @return bool 成功返回true
     */
    public function hMSet($key, array $fields, $expire = 0)
    {
        if (empty($fields)) {
            return false;
        }
        $ret = $this->_redis->hMset($key, $fields);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * hash表操做 - 設置hash字段值
     * @param string $key
     * @param string $field         -   hash字段
     * @param mixed $value                 - 任意值
     * @param int $expire                 -   過時時間,單位秒
     * @return bool 成功返回true
     */
    public function hSet($key, $field, $value, $expire = 0)
    {
        $ret = $this->_redis->hSet($key, $field, $value);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * hash表操做 - 設置hash字段值, 若是字段存在則失敗。
     * @param string $key
     * @param string $field         -   hash字段
     * @param mixed $value                 - 任意值
     * @param int $expire                 -   過時時間,單位秒
     * @return bool 成功返回true, hash字段已經存在
     */
    public function hSetNx($key, $field, $value, $expire = 0)
    {
        $ret = $this->_redis->hSetNx($key, $field, $value);
        if (true === $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * list操做 - 獲取指定位置的元素
     * @param string $key
     * @param int $index            - 索引位置從0開始, -1表明最後一個
     * @return mixed | false     -成功返回結果,失敗返回false
     */
    public function lGet($key, $index)
    {
        return $this->_redis->lGet($key, $index);
    }

    /**
     * list操做 - 在指定元素以前或以後插入元素
     * @param string $key
     * @param mixed $pivot            - 參考元素,在該元素以前或者以後插入, 若是該元素不存在,則放棄插入
     * @param mixed $value            - 待插入元素
     * @param int $posType    - 插入類型,\Redis::BEFORE 或則 \Redis::AFTER
     * @return int  成功返回list元素個數,失敗返回-1表示$pivot不存在。
     */
    public function lInsert($key,  $pivot, $value, $posType = \Redis::AFTER)
    {
        return $this->_redis->lInsert($key, $posType, $pivot, $value);
    }

    /**
     * list操做 - 根據範圍 [$start, $end] 獲取元素
     * 例如:獲取所有數據的範圍條件 [0, -1]
     * @param string $key
     * @param int $start        - 開始位置
     * @param int $end        - 結束位置
     * @return array
     */
    public function lRange($key, $start, $end)
    {
        return $this->_redis->lRange($key, $start, $end);
    }

    /**
     * list操做 - 返回list元素個數
     * @param string $key
     * @return int | false 成功返回元素個數,失敗返回false
     */
    public function lSize($key)
    {
        return $this->_redis->lSize($key);
    }

    /**
     * list操做 - 從head彈出一個元素
     * @param string $key
     * @return mixed | false 成功返回元素,失敗或則爲空返回false
     */
    public function lPop($key)
    {
        return $this->_redis->lPop($key);
    }

    /**
     * list操做 - 從head插入一個元素, list不存在則建立
     * @param string $key
     * @param mixed $value        - 元素
     * @param int $expire        - 超時時間,0不限制
     * @return int | false 成功返回list元素個數
     */
    public function lPush($key, $value, $expire = 0)
    {
        $ret = $this->_redis->lPush($key, $value);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * list操做 - 從head插入一個元素, list不存在則放棄寫入
     * @param string $key
     * @param mixed $value        - 元素
     * @param int $expire        - 超時時間,0不限制
     * @return int | false 成功返回list元素個數
     */
    public function lPushx($key, $value)
    {
        return $this->_redis->lPushx($key, $value);
    }

    /**
     * list操做 - 從list中刪除前面$count個$value元素
     * @param string $key
     * @param string $value        - 待刪除元素, 從head開始查找
     * @param int $count                - 須要刪除幾個元素, 0則所有刪除
     * @return int | false    成功返回刪除元素個數
     */
    public function lRem($key, $value, $count)
    {
        return $this->_redis->lRem($key, $value, $count);
    }

    /**
     * list操做 - 設置list指定位置的值
     * @param string $key
     * @param int $index            - 索引,從0開始
     * @param mixed $value
     * @param int $expire        - 超時時間,0不限制
     * @return bool 成功返回true
     */
    public function lSet($key, $index, $value, $expire = 0)
    {
        $ret =  $this->_redis->lSet($key, $index, $value);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * list操做 - 根據範圍縮小list數據
     * @param string $key
     * @param int $start            - 開始索引
     * @param int $stop            - 結束索引
     * @return bool 成功返回true
     */
    public function lTrim($key, $start, $stop)
    {
        return $this->_redis->lTrim($key, $start, $stop);
    }

    /**
     * list操做 - 從表尾彈出元素
     * @param string $key
     * @return mixed | false 成功返回元素,失敗或則爲空返回false
     */
    public function rPop($key)
    {
        return $this->_redis->rPop($key);
    }

    /**
     * list操做 - 從表尾插入一個元素, list不存在則建立
     * @param string $key
     * @param mixed $value        - 元素
     * @param int $expire        - 超時時間,0不限制
     * @return int | false 成功返回list元素個數
     */
    public function rPush($key, $value, $expire = 0)
    {
        $ret = $this->_redis->rPush($key, $value);
        if (false !== $ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * list操做 - 從表尾插入一個元素, list不存在則放棄寫入
     * @param string $key
     * @param mixed $value        - 元素
     * @return int | false 成功返回list元素個數
     */
    public function rPushX($key, $value)
    {
        return $this->_redis->rPushX($key, $value);
    }

    /**
     * 集合操做 - 添加元素, 若是元素已經存在返回false
     * @param string $key
     * @param string $value        - 容許批量寫入,傳入數組便可,批量寫入,只要有一個元素插入失敗則返回false
     * @param int $expire            - 超時時間, 0不限制
     * @return int | false 成功返回集合元素個數,失敗返回false
     */
    public function sAdd($key, $value, $expire = 0)
    {
        $ret = false;
        if (!empty($value) && is_array($value)) {
            $params = [$key];
            $params = array_merge($params, $value);
            $ret = call_user_func_array(array($this->_redis, 'sAdd'), $params);
        } else {
            $ret = $this->_redis->sAdd($key, $value);
        }

        if ($ret && $expire > 0) {
            $this->_redis->setTimeout($key, $expire);
        }
        return $ret ? true : false;
    }

    /**
     * 集合操做 - 返回全部集合元素
     * @param string $key
     * @return array
     */
    public function sMembers($key)
    {
        return $this->_redis->sMembers($key);
    }

    /**
     * 集合操做 - 檢測集合是否包含指定元素
     * @param string $key
     * @param mixed $value
     * @return bool    存在返回true
     */
    public function sIsMember($key, $value)
    {
        return $this->_redis->sIsMember($key, $value);
    }

    /**
     *  集合操做 - 返回集合元素個數, key不存在返回0
     * @param string $key
     * @return int
     */
    public function sSize($key)
    {
        return $this->_redis->sSize($key);
    }

    /**
     * 集合操做 - 將一個元素從一個集合移動到另一個集合
     * @param string $srcKey        - 源集合
     * @param string $dstKey        - 目標集合
     * @param mixed $member        - 待移動元素
     * @return bool 成功返回true
     */
    public function sMove($srcKey, $dstKey, $member)
    {
        return $this->_redis->sMove($srcKey, $dstKey, $member);
    }

    /**
     * 集合操做 - 隨機彈出一個集合元素
     * @param string $key
     * @return mixed | false        - 成功返回集合元素,失敗返回false
     */
    public function sPop($key)
    {
        return $this->_redis->sPop($key);
    }

    /**
     * 集合操做 - 隨機獲取一個元素,不刪除該元素
     * @param string $key
     * @param int $count        - 隨機返回多少個元素
     * @return mixed |false        - 若是$count=1則返回一個元素,$count > 1則返回一個元素數組
     */
    public function sRandMember($key, $count = 1)
    {
        $ret = false;
        if ($count > 1) {
            $ret = $this->_redis->sRandMember($key, $count);
            //bug處理,srandmember沒有反序列化數據
            if (!empty($ret)) {
                foreach ($ret as $k => $v) {
                    $ret[$k] = unserialize($v);
                }
            }
        }
        else {
            $ret = unserialize($this->_redis->sRandMember($key));
        }
        return $ret;
    }

    /**
     * 集合操做 - 計算key1的差集, 容許傳遞N個參數,最少傳遞2個參數
     * @param string $key1
     * @param string $key2
     * @return boolean|array 成功返回array, 失敗返回false
     */
    public function sDiff($key1, $key2)
    {
        if (func_num_args() < 2) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sDiff"], func_get_args());
    }

    /**
     * 集合操做 - 計算key1的差集, 容許傳遞N個參數,最少傳遞3個參數, 結果保存在$dstKey
     * @param string $dstKey   - 結果保存在該key
     * @param string $key1
     * @param string $key2
     * @return boolean|int 成功返回$dstKey集合元素個數, 失敗返回false
     */
    public function sDiffStore($dstKey, $key1, $key2)
    {
        if (func_num_args() < 3) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sDiffStore"], func_get_args());
    }

    /**
     * 集合操做 - 計算交集, 容許傳遞N個參數,最少傳遞2個參數,只要參與交集運算其中的一個集合key不存在,則返回false
     * @param string $key1
     * @param string $key2
     * @return boolean|array 成功返回array, 失敗返回false
     */
    public function sInter($key1, $key2)
    {
        if (func_num_args() < 2) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sInter"], func_get_args());
    }

    /**
     * 集合操做 - 計算交集, 容許傳遞N個參數,最少傳遞3個參數,只要參與交集運算其中的一個集合key不存在,則返回false
     * @param string $dstKey   - 結果保存在該key
     * @param string $key1
     * @param string $key2
     * @return boolean|int 成功返回$dstKey集合元素個數, 失敗返回false
     */
    public function sInterStore($dstKey, $key1, $key2)
    {
        if (func_num_args() < 3) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sInterStore"], func_get_args());
    }

    /**
     * 集合操做 - 刪除集合元素
     * @param string $key
     * @param mixed $member        - 集合元素, 支持批量刪除,傳遞數組便可
     * @return int 返回刪除元素個數
     */
    public function sRem($key, $member)
    {
        if (!empty($member) && is_array($member)) {
            $params = [$key];
            $params = array_merge($params, $member);
            return call_user_func_array([$this->_redis, 'sRem'], $params);
        }
        return $this->_redis->sRem($key, $member);
    }

    /**
     * 集合操做 - 計算並集, 容許傳遞N個參數,最少傳遞2個參數
     * @param string $key1
     * @param string $key2
     * @return boolean|array 成功返回array, 失敗返回false
     */
    public function sUnion($key1, $key2)
    {
        if (func_num_args() < 2) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sUnion"], func_get_args());
    }

    /**
     * 集合操做 - 計算並集, 容許傳遞N個參數,最少傳遞3個參數
     * @param string $dstKey   - 結果保存在該key
     * @param string $key1
     * @param string $key2
     * @return boolean|int 成功返回$dstKey集合元素個數, 失敗返回false
     */
    public function sUnionStore($dstkey, $key1, $key2)
    {
        if (func_num_args() < 2) {
            return false;
        }
        return call_user_func_array([$this->_redis, "sUnionStore"], func_get_args());
    }

    /**
     * 有序集合操做    - 添加元素
     * @param string $key
     * @param mixed $value
     * @param double $score        - 元素權值
     * @param int $expire            - 超時時間, 0不限制
     * @return bool 成功返回true
     */
    public function zAdd($key, $value, $score, $expire = 0)
    {
        $ret = $this->_redis->zAdd($key, $score, $value);
        if ($ret && $expire > 0) {
            $this->setTimeout($key, $expire);
        }
        return $ret ? true : false;
    }

/**
     * 有序集合操做    - 批量添加元素
     * @param string $key
     * @param array $value        -     集合元素數組,格式: ["元素1" => "權值", "元素2" => "權值"]
     * @param int $expire            - 超時時間, 0不限制
     * @return bool 成功返回true
     */
    public function zAdds($key, array $values, $expire = 0)
    {
        if (empty($values) || !is_array($values)) {
            return false;
        }
        $params = [$key];
        foreach ($values as $k => $score) {
            $params[] = $score;
            $params[] = $k;
        }
        $ret = call_user_func_array([$this->_redis, 'zAdd'], $params);
        if ($ret && $expire > 0) {
            $this->setTimeout($key, $expire);
        }
         return $ret ? true : false;
    }

    /**
     * 有序集合操做    - 返回集合元素個數
     * @param string $key
     * @return int
     */
    public function zSize($key)
    {
        return $this->_redis->zSize($key);
    }

    /**
     * 有序集合操做 - 統計權值在[$start, $end]之間的元素個數
     * @param string $key
     * @param string $start            - 權值最小值,  支持無窮小, Redis::MIN_VALUE
     * @param string $end            - 權值最大值, 支持無窮大, Redis::MAX_VALUE
     * @return int
     */
    public function zCount($key, $start, $end)
    {
        return $this->_redis->zCount($key, $start, $end);
    }

    /**
     * 有序集合操做 - 指定元素的增長權值
     * @param string $key
     * @param mixed $member        - 集合元素
     * @param double $score        - 須要增長的權值
     * @param int $expire            - 超時時間, 0不限制
     * @return int  成功返回新的權值
     */
    public function zIncrBy($key, $member, $score, $expire = 0)
    {
        $ret = $this->_redis->zIncrBy($key, $score, $member);
        if (false !== $ret && $expire > 0) {
            $this->setTimeout($key, $expire);
        }
        return $ret;
    }

    /**
     * 有序集合操做 - 返回[start, end]索引區間的元素, 升序排序
     * @param string $key
     * @param int $start        - 開始索引
     * @param int $end        - 結束索引, -1表明最後一個
     * @return array | false 成功返回集合元素數組,格式: ["元素1" => 權值, "元素2" => 權值 ...]
     */
    public function zRange($key, $start, $end)
    {
        return $this->_redis->zRange($key, $start, $end, true);
    }

    /**
     * 有序集合操做 - 返回[start, end]索引區間的元素, 反序排序
     * @param string $key
     * @param int $start        - 開始索引
     * @param int $end        - 結束索引, -1表明最後一個
     * @return array | false 成功返回集合元素數組,格式: ["元素1" => 權值, "元素2" => 權值 ...]
     */
    public function zRevRange($key, $start, $end)
    {
        return $this->_redis->zRevRange($key, $start, $end, true);
    }



    /**
     * 有序集合操做 - 交集運算,合併相同元素權值時採用以下策略:
     * 1. $weights爲空, 則權值相加,$aggregateType設置無效
     * 2. $weights不爲空,且$weights數組大小必須與$keys數組大小一致,不然失敗。
     *     這種狀況下,首先$keys數組中的每個集合的元素權值分別乘於$weights對應的權值,而後根據$aggregateType肯定相加,取最大值或則最小值.
     *        例子:
     *            //建立有序集合,zuser_list1
     *            Redis::getInstance()->zAdds("zuser_list1", [
     *                                                                                    //元素 => 權值
     *                                                                                    1 => 10,
     *                                                                                    2 => 5,
     *                                                                                    3 => 13,
     *                                                                                    6 => 1,
     *                                                                                    9 => 2,
     *                                                                                    10 => 1,
     *                                                                                ]);
     *            //建立有序集合,zuser_list2
     *            Redis::getInstance()->zAdds("zuser_list2", [
     *                                                                                    1 => 10,
     *                                                                                    2 => 5,
     *                                                                                    3 => 13,
     *                                                                                    60 => 1,
     *                                                                            ]);
     *            //    集合zuser_list1和zuser_list2作交集運算, 結果保存在zuser_dst中
     *            Redis::getInstance()->zInter("zuser_dst", array("zuser_list1", "zuser_list2"), [1,10], Redis::AGGREGATE_TYPE_SUM);
     *            //結果爲:[
     *                                 //元素 => 權值
     *                                  2 => 55,
     *                                  1 => 110,
     *                                  3 => 143,
     *                                 ]
     *             //計算過程:
     *             首先 zuser_list1和zuser_list2直接作交集運算,遇到相同的元素按下面規則處理
     *             由於$weights權值數組爲: [1, 10], 所以zuser_list1集合每一個元素的權值乘於 1,  zuser_list2集合每一個元素的權值乘於 10
     *             由於$aggregateType = Redis::AGGREGATE_TYPE_SUM, 因此相同元素權值相加。
     *
     * @param string $dstKey                                - 結果保存在該key
     * @param array $keys                                    - 須要作交集運算的集合key數組
     * @param array $weights                            - 權值數組,必須與keys數組的大小一致,要麼就爲空
     * @param string $aggregateType                - 相同元素的權值聚合類型,Redis::AGGREGATE_TYPE_SUM 求和
     *                                                                                                               Redis::AGGREGATE_TYPE_MAX 取最大值
     *                                                                                                               Redis::AGGREGATE_TYPE_MIN  取最小值
     * @return int 成功返回$dstKey結果元素個數
     */
    public function zInter($dstKey, array $keys, array $weights = [], $aggregateType = self::AGGREGATE_TYPE_SUM)
    {
        if (empty($weights)) {
            return $this->_redis->zInter($dstKey, $keys);
        }
        return $this->_redis->zInter($dstKey, $keys, $weights, $aggregateType);
    }

    /**
     * 有序集合操做 - 返回權值區間 [start,end]的集合元素, 權值按小到大排序
     * @param string $key
     * @param string $start            - 權值最小值,  支持無窮小, Redis::MIN_VALUE
     * @param string $end            - 權值最大值, 支持無窮大, Redis::MAX_VALUE
     * @param int $offset                - 開始偏移
     * @param int $count                - 分頁大小
     * @return array | false   格式:[
     *                                                             "元素1" => 權值,
     *                                                             "元素2" => 權值,
     *                                                                 ....
     *                                                          ]
     */
    public function zRangeByScore($key, $start, $end, $offset = 0, $count = 0)
    {
        if ($offset >= 0 && $count > 0) {
            return $this->_redis->zRangeByScore($key, $start, $end, ['withscores' => true, 'limit' => [$offset, $count]]);
        }
        return $this->_redis->zRangeByScore($key, $start, $end, ['withscores' => true]);
    }

    /**
     * 有序集合操做 - 返回權值區間 [start,end]的集合元素, 權值按大到小排序
     * @param string $key
     * @param string $start            - 權值最小值,  支持無窮小, Redis::MIN_VALUE
     * @param string $end            - 權值最大值, 支持無窮大, Redis::MAX_VALUE
     * @param int $offset                - 開始偏移
     * @param int $count                - 分頁大小
     * @return array | false   格式:[
     *                                                             "元素1" => 權值,
     *                                                             "元素2" => 權值,
     *                                                                 ....
     *                                                          ]
     */
    public function zRevRangeByScore($key, $start, $end, $offset = 0, $count = 0)
    {
        if ($offset >= 0 && $count > 0) {
            return $this->_redis->zRevRangeByScore($key, $end, $start, ['withscores' => true, 'limit' => [$offset, $count]]);
        }
        return $this->_redis->zRevRangeByScore($key, $end, $start, ['withscores' => true]);
    }

    /**
     * 有序集合操做 - 假定集合元素權值相等的狀況下,集合元素按字典順序查找
     * 例子:
     *         //查找小於等於y的集合元素
     *         Redis::getInstance()->zRangeByLex("key1", "-", "[y")
     *         //查找大於c的元素
     *         Redis::getInstance()->zRangeByLex("key1", "(c", "+")
     *
     * @param string $key
     * @param string $min            - 字母最小值,- 表示負無窮,( 表示大於,[ 表示大於等於
     * @param string $max            - 字母最大值, + 表示正無窮,( 表示大於,[ 表示大於等於
     * @param int $offset                - 元素開始偏移
     * @param int $count                - 分頁大小
     * @return
     */
    public function zRangeByLex($key, $min, $max, $offset = 0, $count = 0)
    {
        if ($offset >= 0 && $count > 0) {
            return $this->_redis->zRangeByLex($key, $min, $max, $offset, $count);
        }
        return $this->_redis->zRangeByLex($key, $min, $max);
    }

    /**
     * 有序集合操做 - 查找正序排名,從0開始計算名次
     * @param string $key
     * @param mixed $member        - 集合元素
     * @return int | false 成功返回名次
     */
    public function zRank($key, $member)
    {
        return $this->_redis->zRank($key,$member);
    }

    /**
     * 有序集合操做 - 查找反序排名,從0開始計算名次
     * @param string $key
     * @param mixed $member        - 集合元素
     * @return int | false 成功返回名次
     */
    public function zRevRank($key, $member)
    {
        return $this->_redis->zRevRank($key,$member);
    }

    /**
     * 有序集合操做 - 刪除集合元素
     * @param string $key
     * @param mixed $member        - 集合元素, 支持批量刪除,傳遞數組便可
     * @return int 返回刪除元素個數
     */
    public function zRem($key, $member)
    {
        if (!empty($member) && is_array($member)) {
            $params = [$key];
            $params = array_merge($params, $member);
            return call_user_func_array([$this->_redis, 'zRem'], $params);
        }
        return $this->_redis->zRem($key, $member);
    }

    /**
     * 有序集合操做 - 刪除這個名次區間[start,end]的元素, 按升序排序
     * @param string $key
     * @param int $start
     * @param int $end
     * @return int | false 成功返回刪除元素個數
     */
    public function zRemRangeByRank($key, $start, $end)
    {
        return $this->_redis->zRemRangeByRank($key, $start, $end);
    }

    /**
     * 有序集合操做 - 刪除這個權值區間[start,end]的元素
     * @param string $key
     * @param string $start            - 權值最小值,  支持無窮小, Redis::MIN_VALUE
     * @param string $end            - 權值最大值, 支持無窮大, Redis::MAX_VALUE
     * @return int | false 成功返回刪除元素個數
     */
    public function zRemRangeByScore($key, $start, $end)
    {
        return $this->_redis->zRemRangeByScore($key, $start, $end);
    }

    /**
     * 有序集合操做 - 獲取指定元素的權值
     * @param string $key
     * @param string $member            - 元素
     * @return double | false 成功返回權值,失敗返回false
     */
    public function zScore($key, $member)
    {
        return $this->_redis->zScore($key, $member);
    }

    /**
     * 有序集合操做 - 並集運算,遇到相同元素合併權值策略,請參考zInter交集權值合併策略。
     * @param string $dstKey                                - 結果保存在該key
     * @param array $keys                                    - 須要作並集運算的集合key數組
     * @param array $weights                            - 權值數組,必須與keys數組的大小一致,要麼就爲空
     * @param string $aggregateType                - 相同元素的權值聚合類型,Redis::AGGREGATE_TYPE_SUM 求和
     *                                                                                                               Redis::AGGREGATE_TYPE_MAX 取最大值
     *                                                                                                               Redis::AGGREGATE_TYPE_MIN  取最小值
     * @return int 成功返回$dstKey結果元素個數
     */
    public function zUnion($dstKey, array $keys, array $weights = [], $aggregateType = self::AGGREGATE_TYPE_SUM)
    {
        if (empty($weights)) {
            return $this->_redis->zUnion($dstKey, $keys);
        }
        return $this->_redis->zUnion($dstKey, $keys, $weights, $aggregateType);
    }

    /**
     * {@inheritDoc}
     * @see CCache::addValue()
     */
    protected function addValue($key, $value, $expire)
    {
        return $this->setNx($key, $value, $expire);
    }

    /**
     * {@inheritDoc}
     * @see CCache::deleteValue()
     */
    protected function deleteValue($key)
    {
        return $this->delete($key);
    }

    /**
     * {@inheritDoc}
     * @see CCache::flushValues()
     */
    protected function flushValues()
    {
        //不支持,禁用
        return true;
    }

    /**
     * {@inheritDoc}
     * @see CCache::generateUniqueKey()
     */
    protected function generateUniqueKey($key)
    {
        return $key;
    }

    /**
     * {@inheritDoc}
     * @see CCache::getValue()
     */
    protected function getValue($key)
    {
        return $this->get($key);
    }

    /**
     * {@inheritDoc}
     * @see CCache::getValues()
     */
    protected function getValues($keys)
    {
        return $this->mget($keys);
    }

    /**
     * {@inheritDoc}
     * @see CCache::setValue()
     */
    protected function setValue($key, $value, $expire)
    {
        return $this->set($key, $value, $expire);
    }
  /**
     * 鏈接redis
     */
    private function _connect()
    {
        if (null === $this->_redis) {
            $this->_redis = new \Redis();
        }

        $ret = false;
        if (true == $this->_conf['persistent']) {
            $ret = $this->_redis->pconnect($this->_conf['host'], $this->_conf['port'], $this->_conf['timeout']);
        } else {
            $ret = $this->_redis->connect($this->_conf['host'], $this->_conf['port'], $this->_conf['timeout']);
        }

        //密碼不爲空, 則須要密碼驗證
        if (!empty($this->_conf['password'])) {
            $ret = $this->_redis->auth($this->_conf['password']);
        }

        //序列化
        $this->_redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
        return $ret;
    }
}
相關文章
相關標籤/搜索