All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gitee.fufu669.service.CacheService Maven / Gradle / Ivy

There is a newer version: 6.666.66021
Show newest version
package com.gitee.fufu669.service;

import com.alibaba.fastjson.JSON;
import com.gitee.fufu669.common.CacheKeyCommon;
import com.gitee.fufu669.utils.CacheAopUtil;
import com.gitee.fufu669.utils.CachePasswordUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Service;
import redis.clients.jedis.*;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import redis.clients.jedis.params.sortedset.ZAddParams;
import redis.clients.jedis.params.sortedset.ZIncrByParams;

import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author wangfupeng
 */
@Lazy
@Service
public class CacheService {

    public static final Logger logger = LoggerFactory.getLogger(CacheService.class);

    @Value("${redis.keyPrefix}")
    public String redisKeyPrefix;

    @Autowired
    @Qualifier("shardedJedisPoolCacheFetchLater")
    private ShardedJedisPool shardedJedisPool;

    @Autowired
    @Qualifier("valueSerializer")
    private RedisSerializer valueSerializer;

    /**
     * 删除指定的key(一个或多个)
     * 起始版本:1.0.0
     * 时间复杂度:O(N) 将要被删除的key的数量,当删除的key是字符串以外的复杂数据类型时比如List,Set,Hash删除这个key的时间复杂度是O(1)。
     * 删除指定的一批keys,如果删除中的某些key不存在,则直接忽略。
     * 返回值
     * integer-reply: 被删除的keys的数量
     */
    public Long del(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.del(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:del():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回key的value
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回key的value。如果key不存在,返回特殊值nil。如果key的value不是string,就返回错误,因为GET只处理string类型的values。
     * 返回值
     * simple-string-reply:key对应的value,或者nil(key不存在时)
     */
    public String get(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.get(key);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:get():key:" + key
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置一个key的value值
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on successful SET operation.
     * 将键key设定为指定的“字符串”值。
     * 如果	key	已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。
     * 当set命令执行成功之后,之前设置的过期时间都将失效
     * 选项
     * 从2.6.12版本开始,redis为SET命令增加了一系列选项:
     * EX seconds – Set the specified expire time, in seconds.
     * PX milliseconds – Set the specified expire time, in milliseconds.
     * NX – Only set the key if it does not already exist.
     * XX – Only set the key if it already exist.
     * EX seconds – 设置键key的过期时间,单位时秒
     * PX milliseconds – 设置键key的过期时间,单位时毫秒
     * NX – 只有键key不存在的时候才会设置key的值
     * XX – 只有键key存在的时候才会设置key的值
     * 注意: 由于SET命令加上选项已经可以完全取代SETNX, SETEX, PSETEX的功能,所以在将来的版本中,redis可能会不推荐使用并且最终抛弃这几个命令。
     * 返回值
     * simple-string-reply:如果SET命令正常执行那么回返回OK,否则如果加了NX 或者 XX选项,但是没有设置条件。那么会返回nil。
     * 例子
     * redis> SET mykey "Hello"
     * OK
     * redis> GET mykey
     * "Hello"
     * redis>
     * 设计模式
     * 注意: 下面这种设计模式并不推荐用来实现redis分布式锁。应该参考the Redlock algorithm的实现,因为这个方法只是复杂一点,但是却能保证更好的使用效果。
     * 命令 SET resource-name anystring NX EX max-lock-time 是一种用 Redis 来实现锁机制的简单方法。
     * 如果上述命令返回OK,那么客户端就可以获得锁(如果上述命令返回Nil,那么客户端可以在一段时间之后重新尝试),并且可以通过DEL命令来释放锁。
     * 客户端加锁之后,如果没有主动释放,会在过期时间之后自动释放。
     * 可以通过如下优化使得上面的锁系统变得更加鲁棒:
     * 不要设置固定的字符串,而是设置为随机的大字符串,可以称为token。
     * 通过脚步删除指定锁的key,而不是DEL命令。
     * 上述优化方法会避免下述场景:a客户端获得的锁(键key)已经由于过期时间到了被redis服务器删除,但是这个时候a客户端还去执行DEL命令。而b客户端已经在a设置的过期时间之后重新获取了这个同样key的锁,那么a执行DEL就会释放了b客户端加好的锁。
     * 解锁脚本的一个例子将类似于以下:
     * if redis.call("get",KEYS[1]) == ARGV[1]
     * then
     * return redis.call("del",KEYS[1])
     * else
     * return 0
     * end
     * 这个脚本执行方式如下:
     * EVAL …script… 1 resource-name token-value
     */
    public String set(String key, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.set(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:set():key:" + key
                        + ":value:" + value
                        + ":result:" + v1
                        + ":exipireSeconds:"
                        + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS + ":costTime:" + timeCost + "ms"
                        + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置一个key的value值,并设置过期时间
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on successful SET operation.
     * 将键key设定为指定的“字符串”值。
     * 如果	key	已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。
     * 当set命令执行成功之后,之前设置的过期时间都将失效
     * 选项
     * 从2.6.12版本开始,redis为SET命令增加了一系列选项:
     * EX seconds – Set the specified expire time, in seconds.
     * PX milliseconds – Set the specified expire time, in milliseconds.
     * NX – Only set the key if it does not already exist.
     * XX – Only set the key if it already exist.
     * EX seconds – 设置键key的过期时间,单位时秒
     * PX milliseconds – 设置键key的过期时间,单位时毫秒
     * NX – 只有键key不存在的时候才会设置key的值
     * XX – 只有键key存在的时候才会设置key的值
     * 注意: 由于SET命令加上选项已经可以完全取代SETNX, SETEX, PSETEX的功能,所以在将来的版本中,redis可能会不推荐使用并且最终抛弃这几个命令。
     * 返回值
     * simple-string-reply:如果SET命令正常执行那么回返回OK,否则如果加了NX 或者 XX选项,但是没有设置条件。那么会返回nil。
     * 例子
     * redis> SET mykey "Hello"
     * OK
     * redis> GET mykey
     * "Hello"
     * redis>
     * 设计模式
     * 注意: 下面这种设计模式并不推荐用来实现redis分布式锁。应该参考the Redlock algorithm的实现,因为这个方法只是复杂一点,但是却能保证更好的使用效果。
     * 命令 SET resource-name anystring NX EX max-lock-time 是一种用 Redis 来实现锁机制的简单方法。
     * 如果上述命令返回OK,那么客户端就可以获得锁(如果上述命令返回Nil,那么客户端可以在一段时间之后重新尝试),并且可以通过DEL命令来释放锁。
     * 客户端加锁之后,如果没有主动释放,会在过期时间之后自动释放。
     * 可以通过如下优化使得上面的锁系统变得更加鲁棒:
     * 不要设置固定的字符串,而是设置为随机的大字符串,可以称为token。
     * 通过脚步删除指定锁的key,而不是DEL命令。
     * 上述优化方法会避免下述场景:a客户端获得的锁(键key)已经由于过期时间到了被redis服务器删除,但是这个时候a客户端还去执行DEL命令。而b客户端已经在a设置的过期时间之后重新获取了这个同样key的锁,那么a执行DEL就会释放了b客户端加好的锁。
     * 解锁脚本的一个例子将类似于以下:
     * if redis.call("get",KEYS[1]) == ARGV[1]
     * then
     * return redis.call("del",KEYS[1])
     * else
     * return 0
     * end
     * 这个脚本执行方式如下:
     * EVAL …script… 1 resource-name token-value
     */
    public String set(String key, String value, int expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.set(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
            return null;
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:set():key:" + key + ":value:" + value
                        + ":result:" + v1
                        + ":exipireSeconds:"
                        + expireSeconds + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
    }

    /*自定义删除指令*/
    public Long remove(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.del(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:remove():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash里面一个字段的值
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 设置 key 指定的哈希集中指定字段的值。
     * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。
     * 如果字段在哈希集中存在,它将被重写。
     * 返回值
     * integer-reply:含义如下
     * 1如果field是一个新的字段
     * 0如果field原来在map里面已经存在
     */
    public Boolean hset(String hashMapkey, String key, String value) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.hset(hashMapkey, key, value + "");
            jedis.expire(hashMapkey, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return v1 == 1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hset():hashMapkey:" + hashMapkey
                        + ":key:" + key
                        + ":value:" + value
                        + ":result:" + v1
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash里面一个字段的值
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 设置 key 指定的哈希集中指定字段的值。
     * 如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。
     * 如果字段在哈希集中存在,它将被重写。
     * 返回值
     * integer-reply:含义如下
     * 1如果field是一个新的字段
     * 0如果field原来在map里面已经存在
     */
    public Long hset(String hashMapkey, String key, String value, int expireSeconds,
                     ShardedJedisPool shardedJedisPool) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.hset(hashMapkey, key, value + "");
            if (expireSeconds > 0) {
                jedis.expire(hashMapkey, expireSeconds);
            }
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hset():hashMapkey:" + hashMapkey + ":key:"
                        + key + ":value:" + value
                        + ":result:" + v1
                        + ":exipireSeconds:" + expireSeconds
                        + ":costTime:" + timeCost + "ms"
                        + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取hash中field的值
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 返回 key 指定的哈希集中该字段所关联的值
     * 返回值
     * bulk-string-reply:该字段所关联的值。当字段不存在或者 key 不存在时返回nil。
     */
    public String hget(String hashMapkey, String key) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.hget(hashMapkey, key);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hget():hashMapkey:" + hashMapkey + ":key:"
                        + key + ":result:" + value
                        + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除一个或多个Hash的field
     * 起始版本:2.0.0
     * 时间复杂度:O(N) N是被删除的字段数量。
     * 从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。
     * 如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回0。
     * 返回值
     * integer-reply: 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域
     * 历史
     * 在 2.4及以上版本中 :可接受多个域作为参数。
     * 小于 2.4版本 的 Redis 每次调用只能移除一个域
     * 要在早期版本中以原子方式从哈希集中移除多个域,可用 MULTI/EXEC块。
     */
    public Long hdel(String hashMapkey, String... fields) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.hdel(hashMapkey, fields);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hdel():hashMapkey:" + hashMapkey + ":fields:"
                        + fields + ":costTime:"
                        + ":result:" + v1
                        + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 将hash中指定域的值增加给定的数字
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 增加 key 指定的哈希集中指定字段的数值。如果 key 不存在,会创建一个新的哈希集并与 key 关联。如果字段不存在,则字段的值在该操作执行前被设置为 0
     * HINCRBY 支持的值的范围限定在 64位 有符号整数
     * 返回值
     * integer-reply:增值操作执行后的该字段的值。
     */
    public Long hincrby(String hashMapkey, String key, Long value) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hincrBy(hashMapkey, key, value);
            jedis.expire(hashMapkey, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hincrby():hashMapkey:" + hashMapkey
                        + ":key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":result:" + result
                        + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 将hash中指定域的值增加给定的数字
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 增加 key 指定的哈希集中指定字段的数值。如果 key 不存在,会创建一个新的哈希集并与 key 关联。如果字段不存在,则字段的值在该操作执行前被设置为 0
     * HINCRBY 支持的值的范围限定在 64位 有符号整数
     * 返回值
     * integer-reply:增值操作执行后的该字段的值。
     */
    public Long hincrby(String hashMapkey, String key, Long value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        hashMapkey = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + hashMapkey;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hincrBy(hashMapkey, key, value);
            if (expireSeconds > 0) {
                jedis.expire(hashMapkey, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:hincrby():hashMapkey:" + hashMapkey
                        + ":key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":result:" + result
                        + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个整数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key对应的数字加decrement。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看命令INCR了解关于增减操作的额外信息。
     * 返回值
     * integer-reply: 增加之后的value值。
     */
    public Long incrby(String key, Long value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrBy(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:incrby():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":result:" + result + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个整数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key对应的数字加decrement。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看命令INCR了解关于增减操作的额外信息。
     * 返回值
     * integer-reply: 增加之后的value值。
     */
    public Long incrby(String key, Long value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrBy(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:incrby():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":result:" + result + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个整数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key对应的数字加decrement。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看命令INCR了解关于增减操作的额外信息。
     * 返回值
     * integer-reply: 增加之后的value值。
     */
    public Long incrby(String key, Integer value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrBy(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:incrby():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":result:" + result + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个整数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key对应的数字加decrement。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看命令INCR了解关于增减操作的额外信息。
     * 返回值
     * integer-reply: 增加之后的value值。
     */
    public Long incrby(String key, Integer value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrBy(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:incrby():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":result:" + result + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 用incr命令做成的一把原子锁,和加锁的过期时间是默认时间6秒钟
     */
    public boolean lock(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.incrBy(key, 1);
            if (v1 == 1) {
                jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_LOCK_DEFAULT_EXPIRED_SECONDS);
                return true;
            } else if (v1 >= 2) {
                if (jedis.ttl(key).equals(-1L)) {
                    /*如果key是设成了永不过期,就把key设成过期*/
                    jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_LOCK_DEFAULT_EXPIRED_SECONDS);
                }
            }
            return false;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:lock():key:" + key
                        + ":result:" + v1
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_LOCK_DEFAULT_EXPIRED_SECONDS
                        + ":costTime:" + timeCost + "ms"
                        + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return false;
    }

    /**
     * 用del做的解锁命令
     */
    public boolean unlock(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.del(key);
            if (v1 == 1) {
                return true;
            }
            return false;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:unlock():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return false;
    }

    /**
     * 用incr命令做成的一把原子锁,和加锁的过期时间
     * 完美的解决了过期问题。
     */
    public boolean lock(String key, int expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.incr(key);
            if (v1 == 1) {
                jedis.expire(key, expireSeconds);
                return true;
            } else if (v1 >= 2) {
                Long ttl = jedis.ttl(key);
                if (ttl.equals(-1L) || ttl > expireSeconds) {
                    /*如果key是设成了永不过期,或者ttl的过期时间比传入值要高,就把key设成传入的正确过期时间*/
                    jedis.expire(key, expireSeconds);
                }
            }
            return false;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:lock():key:" + key + ":exipireSeconds:"
                        + expireSeconds + ":result:" + v1
                        + ":costTime:" + timeCost + "ms"
                        + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return false;
    }

    /**
     * 设置一个key的过期的秒数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 设置key的过期时间,超过时间后,将会自动删除该key。在Redis的术语中一个key的相关超时是不确定的。
     * 超时后只有对key执行DEL命令或者SET命令或者GETSET时才会清除。 这意味着,从概念上讲所有改变key的值的操作都会使他清除。 例如,INCR递增key的值,执行LPUSH操作,或者用HSET改变hash的field所有这些操作都会触发删除动作。
     * 使用PERSIST命令可以清除超时,使其变成一个永久的key。
     * 如果key被RENAME命令修改,相关的超时时间会转移到新key上面。
     * 如果key被RENAME命令修改,比如原来就存在Key_A,然后调用RENAME Key_B Key_A命令,这时不管原来Key_A是永久的还是设置为超时的,都会由Key_B的有效期状态覆盖。
     * 刷新过期时间
     * 对已经有过期时间的key执行EXPIRE操作,将会更新它的过期时间。有很多应用有这种业务场景,例如记录会话的session。
     * 返回值
     * integer-reply, 具体的:
     * 1 如果成功设置过期时间。
     * 0 如果key不存在或者不能设置过期时间。
     */
    public Long expire(String key, int expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.expire(key, expireSeconds);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:expire():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":result:" + v1
                        + ":exipireSeconds:"
                        + expireSeconds + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的左边入队一个或多个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。
     * 可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。
     * 所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     * ##历史
     * = 2.4: 接受多个 value 参数。
     * 版本老于 2.4 的 Redis 只能每条命令 push 一个值。
     */
    public Long lpush(String key, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.lpush(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:lpush():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":value:" + value
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的左边入队一个或多个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。
     * 可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。
     * 所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     * ##历史
     * = 2.4: 接受多个 value 参数。
     * 版本老于 2.4 的 Redis 只能每条命令 push 一个值。
     */
    public Long lpush(String key, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.lpush(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:lpush():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":value:" + value
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获得队列(List)的长度
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回存储在 key 里的list的长度。 如果 key 不存在,那么就被看作是空list,并且返回长度为 0。 当存储在 key 里的值不是一个list的话,会返回error。
     * 返回值
     * integer-reply: key对应的list的长度。
     */
    public Long llen(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.llen(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:llen():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return -1L;
    }

    /**
     * 从队列的右边出队一个元
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 移除并返回存于 key 的 list 的最后一个元素。
     * 返回值
     * bulk-string-reply: 最后一个元素的值,或者当 key 不存在的时候返回 nil。
     */
    public String rpop(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.rpop(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:rpop():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return "";
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, double score, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zadd(key, score, member);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zadd():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":score:" + score + ":member:" + member
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return 0L;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, double score, String member, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zadd(key, score, member);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zadd():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":score:" + score + ":member:" + member
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return 0L;
    }

    /**
     * 从排序的集合中删除一个或多个成员
     * 用于从有序集合里移除给定的成员,并返回备移除成员的数量。
     * 如果指定的KEY不是一个有序集合是,返回一个错误说明。
     * 起始版本:1.2.0
     * 时间复杂度:O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.
     * 当key存在,但是其不是有序集合类型,就返回一个错误。
     * 返回值
     * integer-reply, 如下的整数:
     * 返回的是从有序集合中删除的成员个数,不包括不存在的成员。
     * 历史
     * = 2.4: 接受多个元素。
     * 在2.4之前的版本中,每次只能删除一个成员。
     */
    public Long zrem(String key, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrem(key, members);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrem():key:" + key
                        + ":members:" + arrayToString(members)
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return 0L;
    }

    /**
     * 从排序的集合中删除一个或多个成员
     * 用于从有序集合里移除给定的成员,并返回备移除成员的数量。
     * 如果指定的KEY不是一个有序集合是,返回一个错误说明。
     * 起始版本:1.2.0
     * 时间复杂度:O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.
     * 当key存在,但是其不是有序集合类型,就返回一个错误。
     * 返回值
     * integer-reply, 如下的整数:
     * 返回的是从有序集合中删除的成员个数,不包括不存在的成员。
     * 历史
     * = 2.4: 接受多个元素。
     * 在2.4之前的版本中,每次只能删除一个成员。
     */
    public Long zrem(String key, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrem(key, member);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrem():key:" + key
                        + ":member:" + member
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return 0L;
    }

    public String arrayToString(Set arrays) {
        if (arrays == null) {
            return null;
        }
        return arrayToString(arrays.toArray());
    }

    public String arrayToString(Object[] arrays) {
        if (arrays == null) {
            return null;
        }
        String result = null;
        for (int i = 0; i < arrays.length; i++) {
            result += arrays[i] + ",";
        }
        return result;
    }

    /**
     * 在排序的设置返回的成员范围,通过索引,下令从分数高到低
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。
     * 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
     */
    public Set zrevrangeByRate(String key, double minRate, double maxRate) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Set v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrevrangeByScore(key, maxRate, minRate);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrevrangeByRate():key:" + key
                        + ":minRate:" + minRate + ":maxRate:" + maxRate
                        + ":result:" + arrayToString(v1)
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 根据指定的index返回,返回sorted set的成员列表
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回存储在有序集合key中的指定范围的元素。 返回的元素可以认为是按得分从最低到最高排列。 如果得分相同,将按字典排序。
     * 当你需要元素从最高分到最低分排列时,请参阅ZREVRANGE(相同的得分将使用字典倒序排序)。
     * 参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。
     * 它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。
     * start和stop都是全包含的区间,因此例如ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。
     * 超出范围的索引不会产生错误。 如果start参数的值大于有序集合中的最大索引,或者start > stop,将会返回一个空列表。
     * 如果stop的值大于有序集合的末尾,Redis会将其视为有序集合的最后一个元素。
     * 可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。这样,返回的列表将包含value1,score1,...,valueN,scoreN,而不是value1,...,valueN。
     * 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。
     */
    public Set zrangeByRate(String key, double minRate, double maxRate) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Set v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrevrangeByScore(key, maxRate, minRate);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrangeByRate():key:" + key
                        + ":minRate:" + minRate + ":maxRate:" + maxRate
                        + ":result:" + arrayToString(v1)
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 根据指定的index返回,返回sorted set的成员列表
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回存储在有序集合key中的指定范围的元素。 返回的元素可以认为是按得分从最低到最高排列。 如果得分相同,将按字典排序。
     * 当你需要元素从最高分到最低分排列时,请参阅ZREVRANGE(相同的得分将使用字典倒序排序)。
     * 参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。
     * 它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。
     * start和stop都是全包含的区间,因此例如ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。
     * 超出范围的索引不会产生错误。 如果start参数的值大于有序集合中的最大索引,或者start > stop,将会返回一个空列表。
     * 如果stop的值大于有序集合的末尾,Redis会将其视为有序集合的最后一个元素。
     * 可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。这样,返回的列表将包含value1,score1,...,valueN,scoreN,而不是value1,...,valueN。
     * 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。
     */
    public Set zrange(String key, long minRank, long maxRank) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Set v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrange(key, minRank, maxRank);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrange():key:" + key
                        + ":minRank:" + minRank + ":maxRank:" + maxRank
                        + ":result:" + arrayToString(v1)
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 在排序的设置返回的成员范围,通过索引,下令从分数高到低
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。
     * 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
     */
    public Set zrevrange(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Set v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zrevrange(key, start, end);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zrevrange():key:" + key
                        + ":start:" + start + ":end:" + end
                        + ":result:" + arrayToString(v1)
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 用于返回有序集合包含的成员数量。
     * 获取一个排序的集合中的成员数量
     * 起始版本:1.2.0
     * 时间复杂度:O(1)
     * 返回key的有序集元素个数。
     * 返回值
     * integer-reply: key存在的时候,返回有序集的元素个数,否则返回0。
     */
    public Long zcard(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.zcard(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:zcard():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /*自定义,反序列化一个value并返回结果*/
    public Object getValue(String key) {
        ShardedJedis jedis = null;
        Object value = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        try {
            byte[] bs = null;
            byte[] keyBytes = (key).getBytes();
            jedis = shardedJedisPool.getResource();
            bs = jedis.get(keyBytes);
            if (bs == null) {
                value = null;
            } else {
                value = valueSerializer.deserialize(bs);
            }
            return value;
        } catch (SerializationException e) {
            logger.info(e.getMessage(), e);
            return null;
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("%%%%%%CacheService getValue():key:" + key
                        + ":value:" + JSON.toJSONString(value)
                        + ":costTime:" + timeCost + "ms" + "%%%%%%");
                jedis.close();
            }
        }
    }

    /*自定义,序列化一个value并存入redis*/
    public boolean setValue(String key, Object value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String v1 = null;
        try {
            byte[] bs = null;
            byte[] keyBytes = (key).getBytes();
            jedis = shardedJedisPool.getResource();
            v1 = jedis.set(keyBytes, valueSerializer.serialize(value));
            jedis.expire(keyBytes, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return true;
        } catch (SerializationException e) {
            logger.info(e.getMessage(), e);
            return false;
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("%%%%%%CacheService setValue():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":value:" + JSON.toJSONString(value)
                        + ":result:" + v1
                        + ":costTime:" + timeCost + "ms" + "%%%%%%");
                jedis.close();
            }
        }
    }

    /*自定义,序列化一个value并存入redis*/
    public boolean setValue(String key, Object value, int expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String v1 = null;
        try {
            byte[] bs = null;
            byte[] keyBytes = (key).getBytes();
            jedis = shardedJedisPool.getResource();
            v1 = jedis.set(keyBytes, valueSerializer.serialize(value));
            if (expireSeconds > 0) {
                jedis.expire(keyBytes, expireSeconds);
            }
            return true;
        } catch (SerializationException e) {
            logger.info(e.getMessage(), e);
            return false;
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("%%%%%%CacheService setValue():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":value:" + JSON.toJSONString(value)
                        + ":result:" + v1
                        + ":costTime:" + timeCost + "ms" + "%%%%%%");
                jedis.close();
            }
        }
    }

    /**
     * 获取key的有效时间(单位:秒)
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回key剩余的过期时间。 这种反射能力允许Redis客户端检查指定key在数据集里面剩余的有效期。
     * 在Redis 2.6和之前版本,如果key不存在或者已过期时返回-1。
     * 从Redis2.8开始,错误返回值的结果有如下改变:
     * 如果key不存在或者已过期,返回 -2
     * 如果key存在并且没有设置过期时间(永久有效),返回 -1 。
     * 另见PTTL命令返回相同的信息,只不过他的时间单位是毫秒(仅适用于Redis 2.6及更高版本)。
     * 返回值
     * Integer reply: key有效的秒数(TTL in seconds),或者一个负值的错误 (参考上文)。
     */
    public Long ttl(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long v1 = null;
        try {
            jedis = shardedJedisPool.getResource();
            v1 = jedis.ttl(key);
            return v1;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:ttl():key:" + key
                        + ":result:" + v1
                        + ":costTime:" + timeCost + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash字段值
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the number of fields being set.
     * 设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联
     * 返回值
     * simple-string-reply
     */
    public String hmset(String key, Map hash) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.hmset(key, hash);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hmset():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":hash:" + (hash)
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash字段值
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the number of fields being set.
     * 设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联
     * 返回值
     * simple-string-reply
     */
    public String hmset(String key, Map hash, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.hmset(key, hash);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hmset():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":hash:" + (hash)
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取hash里面指定字段的值
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the number of fields being requested.
     * 返回 key 指定的哈希集中指定字段的值。
     * 对于哈希集中不存在的每个字段,返回 nil 值。因为不存在的keys被认为是一个空的哈希集,对一个不存在的 key 执行 HMGET 将返回一个只含有 nil 值的列表
     * 返回值
     * array-reply:含有给定字段及其值的列表,并保持与请求相同的顺序。
     */
    public List hmget(String key, String... fields) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.hmget(key, fields);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hmget():" +
                        "key:" + key
                        + ":fields:" + (fields)
                        + ":result:" + (value)
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 回显输入的字符串
     * 起始版本:1.0.0
     * 返回消息
     * 返回值
     * Bulk reply
     * 例子
     * redis> ECHO HelloWorld!
     * HelloWorld!
     * redis>
     */
    public String echo(String string) {
        ShardedJedis jedis = null;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.echo(string);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:echo():key:" + string
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 查询一个key是否存在
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回key是否存在。
     * 返回值
     * integer-reply,如下的整数结果
     * 1 如果key存在
     * 0 如果key不存在
     */
    public Boolean exists(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.exists(key);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:exists():key:" + key
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取key的存储类型
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回key所存储的value的数据结构类型,它可以返回string, list, set, zset 和 hash等不同的类型。
     * 返回值
     * simple-string-reply: 返回当前key的数据类型,如果key不存在时返回none。
     */
    public String type(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.type(key);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:type():key:" + key
                        + ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置key的有效时间以毫秒为单位
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 这个命令和EXPIRE命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像EXPIRE命令那样,以秒为单位。
     * 返回值
     * integer-reply, 只有以下两种值:
     * 设置成功,返回 1
     * key 不存在或设置失败,返回 0
     */
    public Long pexpire(String key, long milliseconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.pexpire(key, milliseconds);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:pexpire():key:" + key
                        + ":milliseconds:" + milliseconds +
                        ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 设置一个UNIX时间戳的过期时间
     * 起始版本:1.2.0
     * 时间复杂度:O(1)
     * EXPIREAT 的作用和 EXPIRE类似,都用于为 key 设置生存时间。不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳 Unix timestamp 。
     * 返回值
     * integer-reply,如下的整数结果
     * 1 如果设置了过期时间 0 如果没有设置过期时间,或者不能设置过期时间
     */
    public Long expireAt(String key, long unixTime) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.expireAt(key, unixTime);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:expireAt():key:" + key
                        + ":unixTime:" + unixTime +
                        ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置key的到期UNIX时间戳以毫秒为单位
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * PEXPIREAT 这个命令和EXPIREAT命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像EXPIREAT那样,以秒为单位。
     * 返回值
     * integer-reply, 只有以下两种值:
     * 如果生存时间设置成功,返回 1 。
     * 当 key 不存在或没办法设置生存时间时,返回 0 。 (查看: EXPIRE命令获取更多信息).
     */
    public Long pexpireAt(String key, long millisecondsTimestamp) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.pexpireAt(key, millisecondsTimestamp);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:pexpireAt():key:" + key
                        + ":millisecondsTimestamp:" + millisecondsTimestamp +
                        ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取key的有效毫秒数
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 这个命令类似于TTL命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像TTL命令那样,以秒为单位。
     * 在Redis 2.6和之前版本,如果key不存在或者key存在且无过期时间将返回-1。
     * 从 Redis 2.8开始,错误返回值发送了如下变化:
     * 如果key不存在返回-2
     * 如果key存在且无过期时间返回-1
     * 返回值
     * integer-reply: TTL以毫秒为单位,或者返回一个错误值 (参考上面的描述).
     */
    public Long pttl(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long value = null;
        try {
            jedis = shardedJedisPool.getResource();
            value = jedis.pttl(key);
            return value;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:pttl():key:" + key +
                        ":result:" + value
                        + ":costTime:" + timeCost
                        + "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Sets or clears the bit at offset in the string value stored at key
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 设置或者清空key的value(字符串)在offset处的bit值。
     * 那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。当key不存在的时候,就创建一个新的字符串value。要确保这个字符串大到在offset处有bit值。参数offset需要大于等于0,并且小于232(限制bitmap大小为512)。当key对应的字符串增大的时候,新增的部分bit值都是设置为0。
     * 警告:当set最后一个bit(offset等于232-1)并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。在一台2010MacBook Pro上,offset为232-1(分配512MB)需要~300ms,offset为230-1(分配128MB)
     * 需要~80ms,offset为228-1(分配32MB)需要~30ms,offset为226-1(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETBIT就不会预先得到内存分配。
     * 返回值
     * integer-reply:在offset处原来的bit值
     */
    public Boolean setbit(String key, long offset, boolean value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setbit(key, offset, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:setbit():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * Sets or clears the bit at offset in the string value stored at key
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 设置或者清空key的value(字符串)在offset处的bit值。
     * 那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。当key不存在的时候,就创建一个新的字符串value。要确保这个字符串大到在offset处有bit值。参数offset需要大于等于0,并且小于232(限制bitmap大小为512)。当key对应的字符串增大的时候,新增的部分bit值都是设置为0。
     * 警告:当set最后一个bit(offset等于232-1)并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。在一台2010MacBook Pro上,offset为232-1(分配512MB)需要~300ms,offset为230-1(分配128MB)
     * 需要~80ms,offset为228-1(分配32MB)需要~30ms,offset为226-1(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETBIT就不会预先得到内存分配。
     * 返回值
     * integer-reply:在offset处原来的bit值
     */
    public Boolean setbit(String key, long offset, boolean value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setbit(key, offset, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:setbit():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Sets or clears the bit at offset in the string value stored at key
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 设置或者清空key的value(字符串)在offset处的bit值。
     * 那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。当key不存在的时候,就创建一个新的字符串value。要确保这个字符串大到在offset处有bit值。参数offset需要大于等于0,并且小于232(限制bitmap大小为512)。当key对应的字符串增大的时候,新增的部分bit值都是设置为0。
     * 警告:当set最后一个bit(offset等于232-1)并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。在一台2010MacBook Pro上,offset为232-1(分配512MB)需要~300ms,offset为230-1(分配128MB)
     * 需要~80ms,offset为228-1(分配32MB)需要~30ms,offset为226-1(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETBIT就不会预先得到内存分配。
     * 返回值
     * integer-reply:在offset处原来的bit值
     */
    public Boolean setbit(String key, long offset, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setbit(key, offset, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:setbit():key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Sets or clears the bit at offset in the string value stored at key
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 设置或者清空key的value(字符串)在offset处的bit值。
     * 那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。当key不存在的时候,就创建一个新的字符串value。要确保这个字符串大到在offset处有bit值。参数offset需要大于等于0,并且小于232(限制bitmap大小为512)。当key对应的字符串增大的时候,新增的部分bit值都是设置为0。
     * 警告:当set最后一个bit(offset等于232-1)并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。在一台2010MacBook Pro上,offset为232-1(分配512MB)需要~300ms,offset为230-1(分配128MB)
     * 需要~80ms,offset为228-1(分配32MB)需要~30ms,offset为226-1(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETBIT就不会预先得到内存分配。
     * 返回值
     * integer-reply:在offset处原来的bit值
     */
    public Boolean setbit(String key, long offset, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setbit(key, offset, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:setbit():key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回位的值存储在关键的字符串值的偏移量。
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 返回key对应的string在offset处的bit值 当offset超出了字符串长度的时候,这个字符串就被假定为由0比特填充的连续空间。当key不存在的时候,它就认为是一个空字符串,所以offset总是超出范围,然后value也被认为是由0比特填充的连续空间。到内存分配。
     * 返回值
     * integer-reply:在offset处的bit值
     */
    public Boolean getbit(String key, long offset) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.getbit(key, offset);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:getbit():key:" + key +
                        ":offset:" + offset +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Overwrite part of a string at key starting at the specified offset
     * 起始版本:2.2.0
     * 时间复杂度:O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.
     * 这个命令的作用是覆盖key对应的string的一部分,从指定的offset处开始,覆盖value的长度。
     * 如果offset比当前key对应string还要长,那这个string后面就补0以达到offset。不存在的keys被认为是空字符串,所以这个命令可以确保key有一个足够大的字符串,能在offset处设置value。
     * 注意,offset最大可以是229-1(536870911),因为redis字符串限制在512M大小。
     * 如果你需要超过这个大小,你可以用多个keys。
     * 警告:当set最后一个字节并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。
     * 在一台2010MacBook Pro上,set536870911字节(分配512MB)需要~300ms,set134217728字节(分配128MB)
     * 需要~80ms,set33554432比特位(分配32MB)需要~30ms,set8388608比特(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETRANGE就不会预先得到内存分配。
     * 模式
     * 正因为有了SETRANGE和类似功能的GETRANGE命令,你可以把Redis的字符串当成线性数组,随机访问只要O(1)复杂度。这在很多真实场景应用里非常快和高效。
     * 返回值
     * integer-reply:该命令修改后的字符串长度
     */
    public Long setrange(String key, long offset, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setrange(key, offset, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "setrange()" +
                        ":key:" + key
                        + ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS
                        + ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Overwrite part of a string at key starting at the specified offset
     * 起始版本:2.2.0
     * 时间复杂度:O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.
     * 这个命令的作用是覆盖key对应的string的一部分,从指定的offset处开始,覆盖value的长度。
     * 如果offset比当前key对应string还要长,那这个string后面就补0以达到offset。不存在的keys被认为是空字符串,所以这个命令可以确保key有一个足够大的字符串,能在offset处设置value。
     * 注意,offset最大可以是229-1(536870911),因为redis字符串限制在512M大小。
     * 如果你需要超过这个大小,你可以用多个keys。
     * 警告:当set最后一个字节并且key还没有一个字符串value或者其value是个比较小的字符串时,Redis需要立即分配所有内存,这有可能会导致服务阻塞一会。
     * 在一台2010MacBook Pro上,set536870911字节(分配512MB)需要~300ms,set134217728字节(分配128MB)
     * 需要~80ms,set33554432比特位(分配32MB)需要~30ms,set8388608比特(分配8MB)需要8ms。注意,一旦第一次内存分配完,后面对同一个key调用SETRANGE就不会预先得到内存分配。
     * 模式
     * 正因为有了SETRANGE和类似功能的GETRANGE命令,你可以把Redis的字符串当成线性数组,随机访问只要O(1)复杂度。这在很多真实场景应用里非常快和高效。
     * 返回值
     * integer-reply:该命令修改后的字符串长度
     */
    public Long setrange(String key, long offset, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setrange(key, offset, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "setrange()" +
                        ":key:" + key
                        + ":exipireSeconds:" + expireSeconds
                        + ":offset:" + offset +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 获取存储在key上的值的一个子字符串
     * 起始版本:2.4.0
     * 时间复杂度:O(N) N是字符串长度,复杂度由最终返回长度决定,但由于通过一个字符串创建子字符串是很容易的,它可以被认为是O(1)。
     * 警告:这个命令是被改成GETRANGE的,在小于2.0的Redis版本中叫SUBSTR。 返回key对应的字符串value的子串,这个子串是由start和end位移决定的(两者都在string内)。可以用负的位移来表示从string尾部开始数的下标。所以-1就是最后一个字符,-2就是倒数第二个,以此类推。
     * 这个函数处理超出范围的请求时,都把结果限制在string内。
     * 返回值
     * bulk-reply
     */
    public String getrange(String key, long startOffset, long endOffset) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.getrange(key, startOffset, endOffset);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "getrange()" +
                        ":key:" + key +
                        ":startOffset:" + startOffset +
                        ":endOffset:" + endOffset +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置一个key的value,并获取设置前的值
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
     * 设计模式
     * GETSET可以和INCR一起使用实现支持重置的计数功能。
     * 举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。
     * 这可以通过GETSET mycounter “0”来实现:
     * INCR mycounter
     * GETSET mycounter "0"
     * GET mycounter
     * 返回值
     * bulk-string-reply: 返回之前的旧值,如果之前Key不存在将返回nil。
     */
    public String getSet(String key, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.getSet(key, value);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "getSet()" +
                        ":key:" + key +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置的一个关键的价值,只有当该键不存在
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。
     * 返回值
     * Integer reply, 特定值:
     * 1 如果key被设置了
     * 0 如果key没有被设置
     * 例子
     * redis> SETNX mykey "Hello"
     * (integer) 1
     * redis> SETNX mykey "World"
     * (integer) 0
     * redis> GET mykey
     * "Hello"
     * redis>
     * Design pattern: Locking with !SETNX
     * 设计模式:使用!SETNX加锁
     * Please note that:
     * 请注意:
     * 不鼓励以下模式来实现the Redlock algorithm ,该算法实现起来有一些复杂,但是提供了更好的保证并且具有容错性。
     * 无论如何,我们保留旧的模式,因为肯定存在一些已实现的方法链接到该页面作为引用。而且,这是一个有趣的例子说明Redis命令能够被用来作为编程原语的。
     * 无论如何,即使假设一个单例的加锁原语,但是从 2.6.12 开始,可以创建一个更加简单的加锁原语,相当于使用SET命令来获取锁,并且用一个简单的 Lua 脚本来释放锁。该模式被记录在SET命令的页面中。
     * 也就是说,SETNX能够被使用并且以前也在被使用去作为一个加锁原语。例如,获取键为foo的锁,客户端可以尝试一下操作:
     * SETNX lock.foo 
     * 如果客户端获得锁,SETNX返回1,那么将lock.foo键的Unix时间设置为不在被认为有效的时间。客户端随后会使用DEL lock.foo去释放该锁。
     * 如果SETNX返回0,那么该键已经被其他的客户端锁定。如果这是一个非阻塞的锁,才能立刻返回给调用者,或者尝试重新获取该锁,直到成功或者过期超时。
     * 处理死锁
     * 以上加锁算法存在一个问题:如果客户端出现故障,崩溃或者其他情况无法释放该锁会发生什么情况?这是能够检测到这种情况,因为该锁包含一个Unix时间戳,如果这样一个时间戳等于当前的Unix时间,该锁将不再有效。
     * 当以下这种情况发生时,我们不能调用DEL来删除该锁,并且尝试执行一个SETNX,因为这里存在一个竞态条件,当多个客户端察觉到一个过期的锁并且都尝试去释放它。
     * C1 和 C2 读lock.foo检查时间戳,因为他们执行完SETNX后都被返回了0,因为锁仍然被 C3 所持有,并且 C3 已经崩溃。
     * C1 发送DEL lock.foo
     * C1 发送SETNX lock.foo命令并且成功返回
     * C2 发送DEL lock.foo
     * C2 发送SETNX lock.foo命令并且成功返回
     * 错误:由于竞态条件导致 C1 和 C2 都获取到了锁
     * 幸运的是,可以使用以下的算法来避免这种情况,请看 C4 客户端所使用的好的算法:
     * C4 发送SETNX lock.foo为了获得该锁
     * 已经崩溃的客户端 C3 仍然持有该锁,所以Redis将会返回0给 C4
     * C4 发送GET lock.foo检查该锁是否已经过期。如果没有过期,C4 客户端将会睡眠一会,并且从一开始进行重试操作
     * 另一种情况,如果因为 lock.foo键的Unix时间小于当前的Unix时间而导致该锁已经过期,C4 会尝试执行以下的操作:
     * GETSET lock.foo 
     * 由于GETSET 的语意,C4会检查已经过期的旧值是否仍然存储在lock.foo中。如果是的话,C4 会获得锁
     * 如果另一个客户端,假如为 C5 ,比 C4 更快的通过GETSET操作获取到锁,那么 C4 执行GETSET操作会被返回一个不过期的时间戳。C4 将会从第一个步骤重新开始。请注意:即使 C4 在将来几秒设置该键,这也不是问题。
     * 为了使这种加锁算法更加的健壮,持有锁的客户端应该总是要检查是否超时,保证使用DEL释放锁之前不会过期,因为客户端故障的情况可能是复杂的,不止是崩溃,还会阻塞一段时间,阻止一些操作的执行,并且在阻塞恢复后尝试执行DEL(此时,该LOCK已经被其他客户端所持有)
     */
    public Long setnx(String key, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setnx(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "setnx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 设置的一个关键的价值,只有当该键不存在
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。
     * 返回值
     * Integer reply, 特定值:
     * 1 如果key被设置了
     * 0 如果key没有被设置
     * 例子
     * redis> SETNX mykey "Hello"
     * (integer) 1
     * redis> SETNX mykey "World"
     * (integer) 0
     * redis> GET mykey
     * "Hello"
     * redis>
     * Design pattern: Locking with !SETNX
     * 设计模式:使用!SETNX加锁
     * Please note that:
     * 请注意:
     * 不鼓励以下模式来实现the Redlock algorithm ,该算法实现起来有一些复杂,但是提供了更好的保证并且具有容错性。
     * 无论如何,我们保留旧的模式,因为肯定存在一些已实现的方法链接到该页面作为引用。而且,这是一个有趣的例子说明Redis命令能够被用来作为编程原语的。
     * 无论如何,即使假设一个单例的加锁原语,但是从 2.6.12 开始,可以创建一个更加简单的加锁原语,相当于使用SET命令来获取锁,并且用一个简单的 Lua 脚本来释放锁。该模式被记录在SET命令的页面中。
     * 也就是说,SETNX能够被使用并且以前也在被使用去作为一个加锁原语。例如,获取键为foo的锁,客户端可以尝试一下操作:
     * SETNX lock.foo 
     * 如果客户端获得锁,SETNX返回1,那么将lock.foo键的Unix时间设置为不在被认为有效的时间。客户端随后会使用DEL lock.foo去释放该锁。
     * 如果SETNX返回0,那么该键已经被其他的客户端锁定。如果这是一个非阻塞的锁,才能立刻返回给调用者,或者尝试重新获取该锁,直到成功或者过期超时。
     * 处理死锁
     * 以上加锁算法存在一个问题:如果客户端出现故障,崩溃或者其他情况无法释放该锁会发生什么情况?这是能够检测到这种情况,因为该锁包含一个Unix时间戳,如果这样一个时间戳等于当前的Unix时间,该锁将不再有效。
     * 当以下这种情况发生时,我们不能调用DEL来删除该锁,并且尝试执行一个SETNX,因为这里存在一个竞态条件,当多个客户端察觉到一个过期的锁并且都尝试去释放它。
     * C1 和 C2 读lock.foo检查时间戳,因为他们执行完SETNX后都被返回了0,因为锁仍然被 C3 所持有,并且 C3 已经崩溃。
     * C1 发送DEL lock.foo
     * C1 发送SETNX lock.foo命令并且成功返回
     * C2 发送DEL lock.foo
     * C2 发送SETNX lock.foo命令并且成功返回
     * 错误:由于竞态条件导致 C1 和 C2 都获取到了锁
     * 幸运的是,可以使用以下的算法来避免这种情况,请看 C4 客户端所使用的好的算法:
     * C4 发送SETNX lock.foo为了获得该锁
     * 已经崩溃的客户端 C3 仍然持有该锁,所以Redis将会返回0给 C4
     * C4 发送GET lock.foo检查该锁是否已经过期。如果没有过期,C4 客户端将会睡眠一会,并且从一开始进行重试操作
     * 另一种情况,如果因为 lock.foo键的Unix时间小于当前的Unix时间而导致该锁已经过期,C4 会尝试执行以下的操作:
     * GETSET lock.foo 
     * 由于GETSET 的语意,C4会检查已经过期的旧值是否仍然存储在lock.foo中。如果是的话,C4 会获得锁
     * 如果另一个客户端,假如为 C5 ,比 C4 更快的通过GETSET操作获取到锁,那么 C4 执行GETSET操作会被返回一个不过期的时间戳。C4 将会从第一个步骤重新开始。请注意:即使 C4 在将来几秒设置该键,这也不是问题。
     * 为了使这种加锁算法更加的健壮,持有锁的客户端应该总是要检查是否超时,保证使用DEL释放锁之前不会过期,因为客户端故障的情况可能是复杂的,不止是崩溃,还会阻塞一段时间,阻止一些操作的执行,并且在阻塞恢复后尝试执行DEL(此时,该LOCK已经被其他客户端所持有)
     */
    public Long setnx(String key, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setnx(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "setnx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 设置key-value并设置过期时间(单位:秒)
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期。这个命令等效于执行下面的命令:
     * SET mykey value
     * EXPIRE mykey seconds
     * SETEX是原子的,也可以通过把上面两个命令放到MULTI/EXEC块中执行的方式重现。
     * 相比连续执行上面两个命令,它更快,因为当Redis当做缓存使用时,这个操作更加常用。
     */
    public String setex(String key, int seconds, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.setex(key, seconds, value);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "setex()" +
                        ":key:" + key +
                        ":seconds:" + seconds +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Set the value and expiration in milliseconds of a key
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * PSETEX和SETEX一样,唯一的区别是到期时间以毫秒为单位,而不是秒。
     */
    public String psetex(String key, long milliseconds, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.psetex(key, milliseconds, value);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "psetex()" +
                        ":key:" + key +
                        ":milliseconds:" + milliseconds +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * BLPOP 是阻塞式列表的弹出原语。 它是命令 LPOP 的阻塞版本,这是因为当给定列表内没有任何元素可供弹出的时候, 连接将被 BLPOP 命令阻塞。 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
     * 非阻塞行为
     * 当 BLPOP 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字 key 一起,组成结果返回给调用者。
     * 当存在多个给定 key 时, BLPOP 按给定 key 参数排列的先后顺序,依次检查各个列表。 我们假设 key list1 不存在,而 list2 和 list3 都是非空列表。考虑以下的命令:
     * BLPOP list1 list2 list3 0
     * BLPOP 保证返回一个存在于 list2 里的元素(因为它是从 list1 –> list2 –> list3 这个顺序查起的第一个非空列表)。
     * 阻塞行为
     * 如果所有给定 key 都不存在或包含空列表,那么 BLPOP 命令将阻塞连接, 直到有另一个客户端对给定的这些 key 的任意一个执行 LPUSH 或 RPUSH 命令为止。
     * 一旦有新的数据出现在其中一个列表里,那么这个命令会解除阻塞状态,并且返回 key 和弹出的元素值。
     * 当 BLPOP 命令引起客户端阻塞并且设置了一个非零的超时参数 timeout 的时候, 若经过了指定的 timeout 仍没有出现一个针对某一特定 key 的 push 操作,则客户端会解除阻塞状态并且返回一个 nil 的多组合值(multi-bulk value)。
     * timeout 参数表示的是一个指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。
     * 什么 key 会先被处理?是什么客户端?什么元素?优先顺序细节。
     * 当客户端为多个 key 尝试阻塞的时候,若至少存在一个 key 拥有元素,那么返回的键值对(key/element pair)就是从左到右数第一个拥有一个或多个元素的key。 在这种情况下客户端不会被阻塞。比如对于这个例子 BLPOP key1 key2 key3 key4 0,假设 key2 和 key4 都非空, 那么就会返回 key2 里的一个元素。
     * 当多个客户端为同一个 key 阻塞的时候,第一个被处理的客户端是等待最长时间的那个(即第一个因为该key而阻塞的客户端)。 一旦一个客户端解除阻塞那么它就不会保持任何优先级,当它因为下一个 BLPOP 命令而再次被阻塞的时候,会在处理完那些 被同个 key 阻塞的客户端后才处理它(即从第一个被阻塞的处理到最后一个被阻塞的)。
     * 当一个客户端同时被多个 key 阻塞时,若多个 key 的元素同时可用(可能是因为事务或者某个Lua脚本向多个list添加元素), 那么客户端会解除阻塞,并使用第一个接收到 push 操作的 key(假设它拥有足够的元素为我们的客户端服务,因为有可能存在其他客户端同样是被这个key阻塞着)。 从根本上来说,在执行完每个命令之后,Redis 会把一个所有 key 都获得数据并且至少使一个客户端阻塞了的 list 运行一次。 这个 list
     * 按照新数据的接收时间进行整理,即是从第一个接收数据的 key 到最后一个。在处理每个 key 的时候,只要这个 key 里有元素, Redis就会对所有等待这个key的客户端按照“先进先出”(FIFO)的顺序进行服务。若这个 key 是空的,或者没有客户端在等待这个 key, 那么将会去处理下一个从之前的命令或事务或脚本中获得新数据的 key,如此等等。
     * 当多个元素被 push 进入一个 list 时 BLPOP 的行为
     * 有时候一个 list 会在同一概念的命令的情况下接收到多个元素:
     * 像 LPUSH mylist a b c 这样的可变 push 操作。
     * 在对一个向同一个 list 进行多次 push 操作的 MULTI 块执行完 EXEC 语句后。
     * 使用 Redis 2.6 或者更新的版本执行一个 Lua 脚本。
     * 当多个元素被 push 进入一个被客户端阻塞着的 list 的时候,Redis 2.4 和 Redis 2.6 或者更新的版本所采取行为是不一样的。
     * 对于 Redis 2.6 来说,所采取的行为是先执行多个 push 命令,然后在执行了这个命令之后再去服务被阻塞的客户端。看看下面命令顺序。
     * Client A:   BLPOP foo 0
     * Client B:   LPUSH foo a b c
     * 如果上面的情况是发生在 Redis 2.6 或更高版本的服务器上,客户端 A 会接收到 c 元素,因为在 LPUSH 命令执行后,list 包含了 c,b,a 这三个元素,所以从左边取一个元素就会返回 c。
     * 相反,Redis 2.4 是以不同的方式工作的:客户端会在 push 操作的上下文中被服务,所以当 LPUSH foo a b c 开始往 list 中 push 第一个元素,它就被传送给客户端A,也就是客户端A会接收到 a(第一个被 push 的元素)。
     * Redis 2.4的这种行为会在复制或者持续把数据存入AOF文件的时候引发很多问题,所以为了防止这些问题,很多更一般性的、并且在语义上更简单的行为被引入到 Redis 2.6 中。
     * 需要注意的是,一个Lua脚本或者一个 MULTI / EXEC 块可能会 push 一堆元素进入一个 list 后,再 删除这个 list。 在这种情况下,被阻塞的客户端完全不会被服务,并且只要在执行某个单一命令、事务或者脚本后 list 中没有出现元素,它就会被继续阻塞下去。
     * 在一个 MULTI / EXEC 事务中的 BLPOP
     * BLPOP 可以用于流水线(pipeline,发送多个命令并且批量读取回复),特别是当它是流水线里的最后一个命令的时候,这种设定更加有意义。
     * 在一个 MULTI / EXEC 块里面使用 BLPOP 并没有很大意义,因为它要求整个服务器被阻塞以保证块执行时的原子性,这就阻止了其他客户端执行一个 push 操作。 因此,一个在 MULTI / EXEC 里面的 BLPOP 命令会在 list 为空的时候返回一个 nil 值,这跟超时(timeout)的时候发生的一样。
     * 如果你喜欢科幻小说,那么想象一下时间是以无限的速度在 MULTI / EXEC 块中流逝……
     * 返回值
     * 多批量回复(multi-bulk-reply): 具体来说:
     * 当没有元素的时候会弹出一个 nil 的多批量值,并且 timeout 过期。
     * 当有元素弹出时会返回一个双元素的多批量值,其中第一个元素是弹出元素的 key,第二个元素是 value。
     * 例子
     * redis> DEL list1 list2
     * (integer) 0
     * redis> RPUSH list1 a b c
     * (integer) 3
     * redis> BLPOP list1 list2 0
     * 1) "list1"
     * 2) "a"
     * 可靠的队列
     * 当 BLPOP 返回一个元素给客户端的时候,它也从 list 中把该元素移除。这意味着该元素就只存在于客户端的上下文中:如果客户端在处理这个返回元素的过程崩溃了,那么这个元素就永远丢失了。
     * 在一些我们希望是更可靠的消息传递系统中的应用上,这可能会导致一些问题。在这种时候,请查看 BRPOPLPUSH 命令,这是 BLPOP 的一个变形,它会在把返回元素传给客户端之前先把该元素加入到一个目标 list 中。
     * 模式:事件提醒
     * 用来阻塞 list 的操作有可能是不同的阻塞原语。 比如在某些应用里,你也许会为了等待新元素进入 Redis Set 而阻塞队列,直到有个新元素加入到 Set 中,这样就可以在不轮询的情况下获得元素。 这就要求要有一个 SPOP 的阻塞版本,而这事实上并不可用。但是我们可以通过阻塞 list 操作轻易完成这个任务。
     * 消费者会做的:
     * LOOP forever
     * WHILE SPOP(key) returns elements
     * ... process elements ...
     * END
     * BRPOP helper_key
     * END
     * 而在生产者这角度我们可以这样简单地使用:
     * MULTI
     * SADD key element
     * LPUSH helper_key x
     * EXEC
     */
    public List blpop(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.blpop(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "blpop()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * BLPOP 是阻塞式列表的弹出原语。 它是命令 LPOP 的阻塞版本,这是因为当给定列表内没有任何元素可供弹出的时候, 连接将被 BLPOP 命令阻塞。 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
     * 非阻塞行为
     * 当 BLPOP 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字 key 一起,组成结果返回给调用者。
     * 当存在多个给定 key 时, BLPOP 按给定 key 参数排列的先后顺序,依次检查各个列表。 我们假设 key list1 不存在,而 list2 和 list3 都是非空列表。考虑以下的命令:
     * BLPOP list1 list2 list3 0
     * BLPOP 保证返回一个存在于 list2 里的元素(因为它是从 list1 –> list2 –> list3 这个顺序查起的第一个非空列表)。
     * 阻塞行为
     * 如果所有给定 key 都不存在或包含空列表,那么 BLPOP 命令将阻塞连接, 直到有另一个客户端对给定的这些 key 的任意一个执行 LPUSH 或 RPUSH 命令为止。
     * 一旦有新的数据出现在其中一个列表里,那么这个命令会解除阻塞状态,并且返回 key 和弹出的元素值。
     * 当 BLPOP 命令引起客户端阻塞并且设置了一个非零的超时参数 timeout 的时候, 若经过了指定的 timeout 仍没有出现一个针对某一特定 key 的 push 操作,则客户端会解除阻塞状态并且返回一个 nil 的多组合值(multi-bulk value)。
     * timeout 参数表示的是一个指定阻塞的最大秒数的整型值。当 timeout 为 0 是表示阻塞时间无限制。
     * 什么 key 会先被处理?是什么客户端?什么元素?优先顺序细节。
     * 当客户端为多个 key 尝试阻塞的时候,若至少存在一个 key 拥有元素,那么返回的键值对(key/element pair)就是从左到右数第一个拥有一个或多个元素的key。 在这种情况下客户端不会被阻塞。比如对于这个例子 BLPOP key1 key2 key3 key4 0,假设 key2 和 key4 都非空, 那么就会返回 key2 里的一个元素。
     * 当多个客户端为同一个 key 阻塞的时候,第一个被处理的客户端是等待最长时间的那个(即第一个因为该key而阻塞的客户端)。 一旦一个客户端解除阻塞那么它就不会保持任何优先级,当它因为下一个 BLPOP 命令而再次被阻塞的时候,会在处理完那些 被同个 key 阻塞的客户端后才处理它(即从第一个被阻塞的处理到最后一个被阻塞的)。
     * 当一个客户端同时被多个 key 阻塞时,若多个 key 的元素同时可用(可能是因为事务或者某个Lua脚本向多个list添加元素), 那么客户端会解除阻塞,并使用第一个接收到 push 操作的 key(假设它拥有足够的元素为我们的客户端服务,因为有可能存在其他客户端同样是被这个key阻塞着)。 从根本上来说,在执行完每个命令之后,Redis 会把一个所有 key 都获得数据并且至少使一个客户端阻塞了的 list 运行一次。 这个 list
     * 按照新数据的接收时间进行整理,即是从第一个接收数据的 key 到最后一个。在处理每个 key 的时候,只要这个 key 里有元素, Redis就会对所有等待这个key的客户端按照“先进先出”(FIFO)的顺序进行服务。若这个 key 是空的,或者没有客户端在等待这个 key, 那么将会去处理下一个从之前的命令或事务或脚本中获得新数据的 key,如此等等。
     * 当多个元素被 push 进入一个 list 时 BLPOP 的行为
     * 有时候一个 list 会在同一概念的命令的情况下接收到多个元素:
     * 像 LPUSH mylist a b c 这样的可变 push 操作。
     * 在对一个向同一个 list 进行多次 push 操作的 MULTI 块执行完 EXEC 语句后。
     * 使用 Redis 2.6 或者更新的版本执行一个 Lua 脚本。
     * 当多个元素被 push 进入一个被客户端阻塞着的 list 的时候,Redis 2.4 和 Redis 2.6 或者更新的版本所采取行为是不一样的。
     * 对于 Redis 2.6 来说,所采取的行为是先执行多个 push 命令,然后在执行了这个命令之后再去服务被阻塞的客户端。看看下面命令顺序。
     * Client A:   BLPOP foo 0
     * Client B:   LPUSH foo a b c
     * 如果上面的情况是发生在 Redis 2.6 或更高版本的服务器上,客户端 A 会接收到 c 元素,因为在 LPUSH 命令执行后,list 包含了 c,b,a 这三个元素,所以从左边取一个元素就会返回 c。
     * 相反,Redis 2.4 是以不同的方式工作的:客户端会在 push 操作的上下文中被服务,所以当 LPUSH foo a b c 开始往 list 中 push 第一个元素,它就被传送给客户端A,也就是客户端A会接收到 a(第一个被 push 的元素)。
     * Redis 2.4的这种行为会在复制或者持续把数据存入AOF文件的时候引发很多问题,所以为了防止这些问题,很多更一般性的、并且在语义上更简单的行为被引入到 Redis 2.6 中。
     * 需要注意的是,一个Lua脚本或者一个 MULTI / EXEC 块可能会 push 一堆元素进入一个 list 后,再 删除这个 list。 在这种情况下,被阻塞的客户端完全不会被服务,并且只要在执行某个单一命令、事务或者脚本后 list 中没有出现元素,它就会被继续阻塞下去。
     * 在一个 MULTI / EXEC 事务中的 BLPOP
     * BLPOP 可以用于流水线(pipeline,发送多个命令并且批量读取回复),特别是当它是流水线里的最后一个命令的时候,这种设定更加有意义。
     * 在一个 MULTI / EXEC 块里面使用 BLPOP 并没有很大意义,因为它要求整个服务器被阻塞以保证块执行时的原子性,这就阻止了其他客户端执行一个 push 操作。 因此,一个在 MULTI / EXEC 里面的 BLPOP 命令会在 list 为空的时候返回一个 nil 值,这跟超时(timeout)的时候发生的一样。
     * 如果你喜欢科幻小说,那么想象一下时间是以无限的速度在 MULTI / EXEC 块中流逝……
     * 返回值
     * 多批量回复(multi-bulk-reply): 具体来说:
     * 当没有元素的时候会弹出一个 nil 的多批量值,并且 timeout 过期。
     * 当有元素弹出时会返回一个双元素的多批量值,其中第一个元素是弹出元素的 key,第二个元素是 value。
     * 例子
     * redis> DEL list1 list2
     * (integer) 0
     * redis> RPUSH list1 a b c
     * (integer) 3
     * redis> BLPOP list1 list2 0
     * 1) "list1"
     * 2) "a"
     * 可靠的队列
     * 当 BLPOP 返回一个元素给客户端的时候,它也从 list 中把该元素移除。这意味着该元素就只存在于客户端的上下文中:如果客户端在处理这个返回元素的过程崩溃了,那么这个元素就永远丢失了。
     * 在一些我们希望是更可靠的消息传递系统中的应用上,这可能会导致一些问题。在这种时候,请查看 BRPOPLPUSH 命令,这是 BLPOP 的一个变形,它会在把返回元素传给客户端之前先把该元素加入到一个目标 list 中。
     * 模式:事件提醒
     * 用来阻塞 list 的操作有可能是不同的阻塞原语。 比如在某些应用里,你也许会为了等待新元素进入 Redis Set 而阻塞队列,直到有个新元素加入到 Set 中,这样就可以在不轮询的情况下获得元素。 这就要求要有一个 SPOP 的阻塞版本,而这事实上并不可用。但是我们可以通过阻塞 list 操作轻易完成这个任务。
     * 消费者会做的:
     * LOOP forever
     * WHILE SPOP(key) returns elements
     * ... process elements ...
     * END
     * BRPOP helper_key
     * END
     * 而在生产者这角度我们可以这样简单地使用:
     * MULTI
     * SADD key element
     * LPUSH helper_key x
     * EXEC
     */
    public List blpop(int timeout, String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.blpop(timeout, key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "blpop()" +
                        ":key:" + key +
                        ":timeout:" + timeout +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * BRPOP 是一个阻塞的列表弹出原语。 它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接。
     * 该命令会按照给出的 key 顺序查看 list,并在找到的第一个非空 list 的尾部弹出一个元素。
     * 请在 BLPOP 文档 中查看该命令的准确语义,因为 BRPOP 和 BLPOP 基本是完全一样的,除了它们一个是从尾部弹出元素,而另一个是从头部弹出元素。
     * 返回值
     * 多批量回复(multi-bulk-reply): 具体来说:
     * 当没有元素可以被弹出时返回一个 nil 的多批量值,并且 timeout 过期。
     * 当有元素弹出时会返回一个双元素的多批量值,其中第一个元素是弹出元素的 key,第二个元素是 value。
     */
    public List brpop(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.brpop(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "brpop()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * BRPOP 是一个阻塞的列表弹出原语。 它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接。
     * 该命令会按照给出的 key 顺序查看 list,并在找到的第一个非空 list 的尾部弹出一个元素。
     * 请在 BLPOP 文档 中查看该命令的准确语义,因为 BRPOP 和 BLPOP 基本是完全一样的,除了它们一个是从尾部弹出元素,而另一个是从头部弹出元素。
     * 返回值
     * 多批量回复(multi-bulk-reply): 具体来说:
     * 当没有元素可以被弹出时返回一个 nil 的多批量值,并且 timeout 过期。
     * 当有元素弹出时会返回一个双元素的多批量值,其中第一个元素是弹出元素的 key,第二个元素是 value。
     */
    public List brpop(int timeout, String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.brpop(timeout, key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "brpop()" +
                        ":key:" + key +
                        ":timeout:" + timeout +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 原子减指定的整数
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将key对应的数字减decrement。如果key不存在,操作之前,key就会被置为0。如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看命令INCR了解关于增减操作的额外信息。似。
     * 返回值
     * 返回一个数字:减少之后的value值。
     */
    public Long decrBy(String key, long integer) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.decrBy(key, integer);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "decrBy()" +
                        ":key:" + key +
                        ":integer:" + integer +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 整数原子减1
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。这个操作最大支持在64位有符号的整型数字。
     * 查看命令INCR了解关于增减操作的额外信息。
     * 返回值
     * 数字:减小之后的value
     */
    public Long decr(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.decr(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "decr()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个浮点数
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 通过指定浮点数key来增长浮点数(存放于string中)的值. 当键不存在时,先将其值设为0再操作.下面任一情况都会返回错误:
     * key 包含非法值(不是一个string).
     * 当前的key或者相加后的值不能解析为一个双精度的浮点值.(超出精度范围了)
     * 如果操作命令成功, 相加后的值将替换原值存储在对应的键值上, 并以string的类型返回. string中已存的值或者相加参数可以任意选用指数符号,但相加计算的结果会以科学计数法的格式存储. 无论各计算的内部精度如何, 输出精度都固定为小数点后17位.
     * 返回值
     * Bulk-string-reply: 当前key增加increment后的值。
     */
    public Double incrByFloat(String key, double floatNumber) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrByFloat(key, floatNumber);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "incrByFloat()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":doubleNumber:" + floatNumber +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子增加一个浮点数
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 通过指定浮点数key来增长浮点数(存放于string中)的值. 当键不存在时,先将其值设为0再操作.下面任一情况都会返回错误:
     * key 包含非法值(不是一个string).
     * 当前的key或者相加后的值不能解析为一个双精度的浮点值.(超出精度范围了)
     * 如果操作命令成功, 相加后的值将替换原值存储在对应的键值上, 并以string的类型返回. string中已存的值或者相加参数可以任意选用指数符号,但相加计算的结果会以科学计数法的格式存储. 无论各计算的内部精度如何, 输出精度都固定为小数点后17位.
     * 返回值
     * Bulk-string-reply: 当前key增加increment后的值。
     */
    public Double incrByFloat(String key, double floatNumber, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incrByFloat(key, floatNumber);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "incrByFloat()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":doubleNumber:" + floatNumber +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子加1操作
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 对存储在指定key的数值执行原子的加1操作。
     * 如果指定的key不存在,那么在执行incr操作之前,会先将它的值设定为0。
     * 如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,
     * 那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)。
     * 这个操作仅限于64位的有符号整型数据。
     * 注意: 由于redis并没有一个明确的类型来表示整型数据,所以这个操作是一个字符串操作。
     * 执行这个操作的时候,key对应存储的字符串被解析为10进制的64位有符号整型数据。
     * 事实上,Redis 内部采用整数形式(Integer representation)来存储对应的整数值,
     * 所以对该类字符串值实际上是用整数保存,也就不存在存储整数的字符串表示(String representation)所带来的额外消耗。
     * 返回值
     * integer-reply:执行递增操作后key对应的值。
     */
    public Long incr(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incr(key);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "incr()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 执行原子加1操作
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 对存储在指定key的数值执行原子的加1操作。
     * 如果指定的key不存在,那么在执行incr操作之前,会先将它的值设定为0。
     * 如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,
     * 那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)。
     * 这个操作仅限于64位的有符号整型数据。
     * 注意: 由于redis并没有一个明确的类型来表示整型数据,所以这个操作是一个字符串操作。
     * 执行这个操作的时候,key对应存储的字符串被解析为10进制的64位有符号整型数据。
     * 事实上,Redis 内部采用整数形式(Integer representation)来存储对应的整数值,
     * 所以对该类字符串值实际上是用整数保存,也就不存在存储整数的字符串表示(String representation)所带来的额外消耗。
     * 返回值
     * integer-reply:执行递增操作后key对应的值。
     */
    public Long incr(String key, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.incr(key);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "incr()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 追加一个值到key上
     * 起始版本:2.0.0
     * 时间复杂度:O(1)。均摊时间复杂度是O(1), 因为redis用的动态字符串的库在每次分配空间的时候会增加一倍的可用空闲空间,所以在添加的value较小而且已经存在的 value是任意大小的情况下,均摊时间复杂度是O(1) 。
     * 如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
     * 返回值
     * Integer reply:返回append后字符串值(value)的长度。
     */
    public Long append(String key, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.append(key, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "append()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 追加一个值到key上
     * 起始版本:2.0.0
     * 时间复杂度:O(1)。均摊时间复杂度是O(1), 因为redis用的动态字符串的库在每次分配空间的时候会增加一倍的可用空闲空间,所以在添加的value较小而且已经存在的 value是任意大小的情况下,均摊时间复杂度是O(1) 。
     * 如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
     * 返回值
     * Integer reply:返回append后字符串值(value)的长度。
     */
    public Long append(String key, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.append(key, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "append()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 该指令只要用于获取字符串的字串,在Redis2.0版本之前,叫做SUBSTR。strat和end是字串的起始和结束的位置,可以用负数来表示距离string尾部的未知的下标。
     * -1是最后一个字符,-2是底数第二个字符。
     * 需要注意的有两点:
     * 字串包括了start和end这两个位置的字符。在Python中是不包含end的。
     * 当给出的start和end超出了string的范围时,指令只会返回在string内的结果。
     */
    public String substr(String key, int start, int end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.substr(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "substr()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash的一个字段,只有当这个字段不存在时有效
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段已存在,该操作无效果。
     * 返回值
     * integer-reply:含义如下
     * 1:如果字段是个新的字段,并成功赋值
     * 0:如果哈希集中已存在该字段,没有操作被执行
     */
    public Long hsetnx(String key, String field, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hsetnx(key, field, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hsetnx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":field:" + field +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置hash的一个字段,只有当这个字段不存在时有效
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段已存在,该操作无效果。
     * 返回值
     * integer-reply:含义如下
     * 1:如果字段是个新的字段,并成功赋值
     * 0:如果哈希集中已存在该字段,没有操作被执行
     */
    public Long hsetnx(String key, String field, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hsetnx(key, field, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hsetnx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":field:" + field +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 将hash中指定域的值增加给定的浮点数
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 为指定key的hash的field字段值执行float类型的increment加。如果field不存在,则在执行该操作前设置为0.如果出现下列情况之一,则返回错误:
     * field的值包含的类型错误(不是字符串)。
     * 当前field或者increment不能解析为一个float类型。
     * 此命令的确切行为与INCRBYFLOAT命令相同,请参阅INCRBYFLOAT命令获取更多信息。
     * 返回值
     * bulk-string-reply: field执行increment加后的值
     */
    public Double hincrByFloat(String key, String field, double value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hincrByFloat(key, field, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hincrByFloat()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":field:" + field +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 将hash中指定域的值增加给定的浮点数
     * 起始版本:2.6.0
     * 时间复杂度:O(1)
     * 为指定key的hash的field字段值执行float类型的increment加。如果field不存在,则在执行该操作前设置为0.如果出现下列情况之一,则返回错误:
     * field的值包含的类型错误(不是字符串)。
     * 当前field或者increment不能解析为一个float类型。
     * 此命令的确切行为与INCRBYFLOAT命令相同,请参阅INCRBYFLOAT命令获取更多信息。
     * 返回值
     * bulk-string-reply: field执行increment加后的值
     */
    public Double hincrByFloat(String key, String field, double value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hincrByFloat(key, field, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hincrByFloat()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":field:" + field +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 判断field是否存在于hash中
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 返回hash里面field是否存在
     * 返回值
     * integer-reply, 含义如下:
     * 1 hash里面包含该field。
     * 0 hash里面不包含该field或者key不存在。
     */
    public Boolean hexists(String key, String field) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hexists(key, field);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hexists()" +
                        ":key:" + key +
                        ":field:" + field +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取hash里所有字段的数量
     * 起始版本:2.0.0
     * 时间复杂度:O(1)
     * 返回 key 指定的哈希集包含的字段的数量。
     * 返回值
     * integer-reply: 哈希集中字段的数量,当 key 指定的哈希集不存在时返回 0
     */
    public Long hlen(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hlen(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hlen()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取hash的所有字段
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the size of the hash.
     * 返回 key 指定的哈希集中所有字段的名字。
     * 返回值
     * array-reply:哈希集中的字段列表,当 key 指定的哈希集不存在时返回空列表。
     */
    public Set hkeys(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hkeys(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hkeys()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获得hash的所有值
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the size of the hash.
     * 返回 key 指定的哈希集中所有字段的值。
     * 返回值
     * array-reply:哈希集中的值的列表,当 key 指定的哈希集不存在时返回空列表。
     */
    public List hvals(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hvals(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hvals()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从hash中读取全部的域和值
     * 起始版本:2.0.0
     * 时间复杂度:O(N) where N is the size of the hash.
     * 返回 key 指定的哈希集中所有的字段和值。返回值中,每个字段名的下一个是它的值,所以返回值的长度是哈希集大小的两倍
     * 返回值
     * array-reply:哈希集中字段和值的列表。当 key 指定的哈希集不存在时返回空列表。
     */
    public Map hgetAll(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Map result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hgetAll(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "hgetAll()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的右边入队一个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是一个列表,那么会返回一个错误。
     * 可以使用一个命令把多个元素打入队列,只需要在命令后面指定多个参数。元素是从左到右一个接一个从列表尾部插入。
     * 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。
     * 返回值
     * integer-reply: 在 push 操作后的列表长度。
     * 历史
     * = 2.4: 接受多个 value 参数。
     * 在老于 2.4 的 Redis 版本中,一条命令只能 push 单一个值。
     */
    public Long rpush(String key, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.rpush(key, strings);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "rpush()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的右边入队一个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是一个列表,那么会返回一个错误。
     * 可以使用一个命令把多个元素打入队列,只需要在命令后面指定多个参数。元素是从左到右一个接一个从列表尾部插入。
     * 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。
     * 返回值
     * integer-reply: 在 push 操作后的列表长度。
     * 历史
     * = 2.4: 接受多个 value 参数。
     * 在老于 2.4 的 Redis 版本中,一条命令只能 push 单一个值。
     */
    public Long rpush(String key, Integer expireSeconds, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.rpush(key, strings);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "rpush()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的左边入队一个或多个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。
     * 可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。 所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     * ##历史
     * = 2.4: 接受多个 value 参数。
     * 版本老于 2.4 的 Redis 只能每条命令 push 一个值。
     */
    public Long lpush(String key, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lpush(key, strings);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "lpush()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的左边入队一个或多个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。
     * 可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。元素是从最左端的到最右端的、一个接一个被插入到 list 的头部。 所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     * ##历史
     * = 2.4: 接受多个 value 参数。
     * 版本老于 2.4 的 Redis 只能每条命令 push 一个值。
     */
    public Long lpush(String key, Integer expireSeconds, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lpush(key, strings);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "lpush()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 当队列存在时,从队到左边入队一个元素
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 只有当 key 已经存在并且存着一个 list 的时候,在这个 key 下面的 list 的头部插入 value。
     * 与 LPUSH 相反,当 key 不存在的时候不会进行任何操作。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     */
    public Long lpushx(String key, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lpushx(key, strings);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "lpushx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 当队列存在时,从队到左边入队一个元素
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 只有当 key 已经存在并且存着一个 list 的时候,在这个 key 下面的 list 的头部插入 value。
     * 与 LPUSH 相反,当 key 不存在的时候不会进行任何操作。
     * 返回值
     * integer-reply: 在 push 操作后的 list 长度。
     */
    public Long lpushx(String key, Integer expireSeconds, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lpushx(key, strings);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "lpushx()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取指定key值的长度
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 返回key的string类型value的长度。如果key对应的非string类型,就返回错误。
     * 返回值
     * integer-reply:key对应的字符串value的长度,或者0(key不存在)
     */
    public Long strlen(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.strlen(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        "strlen()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 移动一个key到另一个数据库
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 将当前数据库的 key 移动到给定的数据库 db 当中。
     * 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。
     * 因此,也可以利用这一特性,将 MOVE 当作锁(locking)原语(primitive)。
     * 返回值
     * integer-reply:
     * 移动成功返回 1
     * 失败则返回 0
     */
    public Long move(String key, int dbIndex) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.move(key, dbIndex);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":dbIndex:" + dbIndex +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的右边入队一个元素,仅队列存在时有效
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 将值 value 插入到列表 key 的表尾, 当且仅当 key 存在并且是一个列表。 和 RPUSH 命令相反, 当 key 不存在时,RPUSHX 命令什么也不做。
     * 返回值
     * integer-reply: RPUSHX 命令执行之后,表的长度。
     */
    public Long rpushx(String key, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.rpushx(key, strings);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的右边入队一个元素,仅队列存在时有效
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 将值 value 插入到列表 key 的表尾, 当且仅当 key 存在并且是一个列表。 和 RPUSH 命令相反, 当 key 不存在时,RPUSHX 命令什么也不做。
     * 返回值
     * integer-reply: RPUSHX 命令执行之后,表的长度。
     */
    public Long rpushx(String key, Integer expireSeconds, String... strings) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.rpushx(key, strings);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":strings:" + (strings) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 移除key的过期时间
     * 起始版本:2.2.0
     * 时间复杂度:O(1)
     * 移除给定key的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
     * 返回值
     * integer-reply, 只有以下两种值:
     * 当生存时间移除成功时,返回 1 .
     * 如果 key 不存在或 key 没有设置生存时间,返回 0 .
     */
    public Long persist(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.persist(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从列表中获取指定返回的元素
     * 起始版本:1.0.0
     * 时间复杂度:O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.
     * 返回存储在 key 的列表里指定范围内的元素。 start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。
     * 偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。
     * 在不同编程语言里,关于求范围函数的一致性
     * 需要注意的是,如果你有一个list,里面的元素是从0到100,那么 LRANGE list 0 10 这个命令会返回11个元素,即最右边的那个元素也会被包含在内。
     * 在你所使用的编程语言里,这一点可能是也可能不是跟那些求范围有关的函数都是一致的。(像Ruby的 Range.new,Array#slice 或者Python的 range() 函数。)
     * 超过范围的下标
     * 当下标超过list范围的时候不会产生error。
     * 如果start比list的尾部下标大的时候,会返回一个空列表。
     * 如果stop比list的实际尾部大的时候,Redis会当它是最后一个元素的下标。
     * 返回值
     * array-reply: 指定范围里的列表元素。
     */
    public List lrange(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lrange(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 修剪到指定范围内的清单
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the number of elements to be removed by the operation.
     * 修剪(trim)一个已存在的 list,这样 list 就会只包含指定范围的指定元素。start 和 stop 都是由0开始计数的, 这里的 0 是列表里的第一个元素(表头),1 是第二个元素,以此类推。
     * 例如: LTRIM foobar 0 2 将会对存储在 foobar 的列表进行修剪,只保留列表里的前3个元素。
     * start 和 end 也可以用负数来表示与表尾的偏移量,比如 -1 表示列表里的最后一个元素, -2 表示倒数第二个,等等。
     * 超过范围的下标并不会产生错误:如果 start 超过列表尾部,或者 start > end,结果会是列表变成空表(即该 key 会被移除)。 如果 end 超过列表尾部,Redis 会将其当作列表的最后一个元素。
     * LTRIM 的一个常见用法是和 LPUSH / RPUSH 一起使用。 例如:
     * LPUSH mylist someelement
     * LTRIM mylist 0 99
     * 这一对命令会将一个新的元素 push 进列表里,并保证该列表不会增长到超过100个元素。这个是很有用的,比如当用 Redis 来存储日志。 需要特别注意的是,当用这种方式来使用 LTRIM 的时候,操作的复杂度是 O(1) , 因为平均情况下,每次只有一个元素会被移除。
     * 返回值
     * simple-string-reply
     */
    public String ltrim(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.ltrim(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取一个元素,通过其索引列表
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the number of elements to traverse to get to the element at index. This makes asking for the first or the last element of the list O(1).
     * 返回列表里的元素的索引 index 存储在 key 里面。
     * 下标是从0开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。
     * 负数索引用于指定从列表尾部开始索引的元素。
     * 在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。
     * 当 key 位置的值不是一个列表的时候,会返回一个error。
     * 返回值
     * bulk-reply:请求的对应元素,或者当 index 超过范围的时候返回 nil。
     */
    public String lindex(String key, long index) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lindex(key, index);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":index:" + index +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置队列里面一个元素的值
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1).
     * 设置 index 位置的list元素的值为 value。 更多关于 index 参数的信息,详见 LINDEX。
     * 当index超出范围时会返回一个error。
     * 返回值
     * simple-string-reply
     */
    public String lset(String key, long index, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lset(key, index, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":index:" + index +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 设置队列里面一个元素的值
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1).
     * 设置 index 位置的list元素的值为 value。 更多关于 index 参数的信息,详见 LINDEX。
     * 当index超出范围时会返回一个error。
     * 返回值
     * simple-string-reply
     */
    public String lset(String key, long index, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lset(key, index, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":index:" + index +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从列表中删除元素
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the length of the list.
     * 从存于 key 的列表里移除前 count 次出现的值为 value 的元素。 这个 count 参数通过下面几种方式影响这个操作:
     * count > 0: 从头往尾移除值为 value 的元素。
     * count < 0: 从尾往头移除值为 value 的元素。
     * count = 0: 移除所有值为 value 的元素。
     * 比如, LREM list -2 “hello” 会从存于 list 的列表里移除最后两个出现的 “hello”。
     * 需要注意的是,如果list里没有存在key就会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。
     * 返回值
     * integer-reply: 被移除的元素个数。
     */
    public Long lrem(String key, long count, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lrem(key, count, value);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":count:" + count +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从队列的左边出队一个元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 移除并且返回 key 对应的 list 的第一个元素。
     * 返回值
     * bulk-string-reply: 返回第一个元素的值,或者当 key 不存在时返回 nil。
     */
    public String lpop(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.lpop(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加一个或者多个元素到集合(set)里
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the number of members to be added.
     * 添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
     * 如果key 的类型不是集合则返回错误.
     * 返回值
     * integer-reply:返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
     * ##历史
     * = 2.4: 接受多个member 参数.
     * Redis 2.4 以前的版本每次只能添加一个member元素.
     */
    public Long sadd(String key, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sadd(key, members);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":members:" + (members) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加一个或者多个元素到集合(set)里
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the number of members to be added.
     * 添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
     * 如果key 的类型不是集合则返回错误.
     * 返回值
     * integer-reply:返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
     * ##历史
     * = 2.4: 接受多个member 参数.
     * Redis 2.4 以前的版本每次只能添加一个member元素.
     */
    public Long sadd(String key, Integer expireSeconds, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sadd(key, members);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":members:" + (members) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取集合里面的所有元素
     * 起始版本:1.0.0
     * 时间复杂度:O(N) where N is the set cardinality.
     * 返回key集合所有的元素.
     * 该命令的作用与使用一个参数的SINTER 命令作用相同.
     * 返回值
     * array-reply:集合中的所有元素.
     */
    public Set smembers(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.smembers(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从集合里删除一个或多个元素
     * 起始版本:1.0.0
     * 时间复杂度:Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.
     * 仅提供key参数,那么随机返回key集合中的一个元素.
     * Redis 2.6开始,可以接受 count 参数,如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,当count是负数,则会返回一个包含count的绝对值的个数元素的数组,如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.
     * 仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
     * 返回值
     * bulk-string-reply: 不使用count 参数的情况下该命令返回随机的元素,如果key不存在则返回nil。
     * array-reply: 使用count参数,则返回一个随机的元素数组,如果key不存在则返回一个空的数组。
     */
    public Long srem(String key, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.srem(key, members);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除并获取一个集合里面的元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 从存储在key的集合中移除并返回一个或多个随机元素。
     * 此操作与SRANDMEMBER类似,它从一个集合中返回一个或多个随机元素,但不删除元素。
     * count参数将在更高版本中提供,但是在2.6、2.8、3.0中不可用。
     * 返回值
     * bulk-string-reply:被删除的元素,或者当key不存在时返回nil。
     */
    public String spop(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.spop(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除并获取一个集合里面的元素
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 从存储在key的集合中移除并返回一个或多个随机元素。
     * 此操作与SRANDMEMBER类似,它从一个集合中返回一个或多个随机元素,但不删除元素。
     * count参数将在更高版本中提供,但是在2.6、2.8、3.0中不可用。
     * 返回值
     * bulk-string-reply:被删除的元素,或者当key不存在时返回nil。
     */
    public Set spop(String key, long count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.spop(key, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":count:" + (count) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取集合里面的元素数量
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回集合存储的key的基数 (集合元素的数量).
     * 返回值
     * integer-reply: 集合的基数(元素的数量),如果key不存在,则返回 0.
     */
    public Long scard(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.scard(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 确定一个给定的值是一个集合的成员
     * 起始版本:1.0.0
     * 时间复杂度:O(1)
     * 返回成员 member 是否是存储的集合 key的成员.
     * 返回值
     * integer-reply,详细说明:
     * 如果member元素是集合key的成员,则返回1
     * 如果member元素不是key的成员,或者集合key不存在,则返回0
     */
    public Boolean sismember(String key, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Boolean result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sismember(key, member);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + (member) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从集合里面随机获取一个元素,不删除元素
     * 起始版本:1.0.0
     * 时间复杂度:Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.
     * 仅提供key参数,那么随机返回key集合中的一个元素.
     * Redis 2.6开始,可以接受 count 参数,
     * 如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,
     * 如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,
     * 当count是负数,则会返回一个包含count的绝对值的个数元素的数组,
     * 如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.
     * 仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
     * 返回值
     * bulk-string-reply: 不使用count 参数的情况下该命令返回随机的元素,如果key不存在则返回nil。
     * array-reply: 使用count参数,则返回一个随机的元素数组,如果key不存在则返回一个空的数组。
     */
    public String srandmember(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        String result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.srandmember(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 从集合里面随机获取一个元素,不删除元素
     * 起始版本:1.0.0
     * 时间复杂度:Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.
     * 仅提供key参数,那么随机返回key集合中的一个元素.
     * Redis 2.6开始,可以接受 count 参数,
     * 如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,
     * 如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,
     * 当count是负数,则会返回一个包含count的绝对值的个数元素的数组,
     * 如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.
     * 仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作.
     * 返回值
     * bulk-string-reply: 不使用count 参数的情况下该命令返回随机的元素,如果key不存在则返回nil。
     * array-reply: 使用count参数,则返回一个随机的元素数组,如果key不存在则返回一个空的数组。
     */
    public List srandmember(String key, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.srandmember(key, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":count:" + (count) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, double score, String member, ZAddParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, score, member, params);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, double score, String member, ZAddParams params, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, score, member, params);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, Map scoreMembers) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, scoreMembers);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":scoreMembers:" + (scoreMembers) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, Map scoreMembers, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, scoreMembers);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":scoreMembers:" + (scoreMembers) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, Map scoreMembers, ZAddParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, scoreMembers, params);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":scoreMembers:" + (scoreMembers) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) for each item added, where N is the number of elements in the sorted set.
     * 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。
     * 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
     * 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。
     * 如果key存在,但是类型不是有序集合,将会返回一个错误应答。
     * 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
     * ZADD 参数(options) (>= Redis 3.0.2)
     * ZADD 命令在key后面分数/成员(score/member)对前面支持一些参数,他们是:
     * XX: 仅仅更新存在的成员,不添加新成员。
     * NX: 不更新存在的成员。只添加新成员。
     * CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
     * INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
     * 分数可以精确的表示的整数的范围
     * Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。
     * 或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
     * Sorted sets 101
     * 有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。
     * 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。
     * 获取一个成员当前的分数可以使用ZSCORE命令,也可以用它来验证成员是否存在。
     * 更多关于有序集合的信息请参考数据类型-有序集合。
     * 相同分数的成员
     * 有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。
     * 当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,
     * 然后,相同分数的成员按照字典规则相对排序)。
     * 字典顺序排序用的是二进制,它比较的是字符串的字节数组。
     * 如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用ZRANGEBYLEX命令
     * (注:范围查询分数可以使用ZRANGEBYSCORE命令)。
     * 返回值
     * Integer reply, 包括:
     * 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
     * 如果指定INCR参数, 返回将会变成bulk-string-reply :
     * 成员的新分数(双精度的浮点型数字)字符串。
     */
    public Long zadd(String key, Map scoreMembers, ZAddParams params, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zadd(key, scoreMembers, params);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":scoreMembers:" + (scoreMembers) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 增量的一名成员在排序设置的评分
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) where N is the number of elements in the sorted set.
     * 为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。
     * 如果key不存在,就创建一个只含有指定member成员的有序集合。
     * 当key不是有序集类型时,返回一个错误。
     * score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。也有可能给一个负数来减少score的值。
     * 返回值
     * Bulk string reply: member成员的新score值,以字符串形式表示。
     */
    public Double zincrby(String key, double score, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zincrby(key, score, member);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 增量的一名成员在排序设置的评分
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) where N is the number of elements in the sorted set.
     * 为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。
     * 如果key不存在,就创建一个只含有指定member成员的有序集合。
     * 当key不是有序集类型时,返回一个错误。
     * score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。也有可能给一个负数来减少score的值。
     * 返回值
     * Bulk string reply: member成员的新score值,以字符串形式表示。
     */
    public Double zincrby(String key, double score, String member, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zincrby(key, score, member);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 增量的一名成员在排序设置的评分
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) where N is the number of elements in the sorted set.
     * 为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。
     * 如果key不存在,就创建一个只含有指定member成员的有序集合。
     * 当key不是有序集类型时,返回一个错误。
     * score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。也有可能给一个负数来减少score的值。
     * 返回值
     * Bulk string reply: member成员的新score值,以字符串形式表示。
     */
    public Double zincrby(String key, double score, String member, ZIncrByParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zincrby(key, score, member, params);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 增量的一名成员在排序设置的评分
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)) where N is the number of elements in the sorted set.
     * 为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。
     * 如果key不存在,就创建一个只含有指定member成员的有序集合。
     * 当key不是有序集类型时,返回一个错误。
     * score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。也有可能给一个负数来减少score的值。
     * 返回值
     * Bulk string reply: member成员的新score值,以字符串形式表示。
     */
    public Double zincrby(String key, double score, String member, ZIncrByParams params, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zincrby(key, score, member, params);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":score:" + (score) +
                        ":member:" + (member) +
                        ":params:" + (params) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 确定在排序集合成员的索引
     * 起始版本:2.0.0
     * 时间复杂度:O(log(N))
     * 返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。排名以0为底,也就是说,score值最小的成员排名为0。
     * 使用ZREVRANK命令可以获得成员按score值递减(从大到小)排列的排名。
     * 返回值
     * 如果member是有序集key的成员,返回integer-reply:member的排名。
     * 如果member不是有序集key的成员,返回bulk-string-reply: nil。
     */
    public Long zrank(String key, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrank(key, member);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + (member) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 确定指数在排序集的成员,下令从分数高到低
     * 起始版本:2.0.0
     * 时间复杂度:O(log(N))
     * 返回有序集key中成员member的排名,其中有序集成员按score值从大到小排列。排名以0为底,也就是说,score值最大的成员排名为0。
     * 使用ZRANK命令可以获得成员按score值递增(从小到大)排列的排名。
     * 返回值:
     * 如果member是有序集key的成员,返回integer-reply:member的排名。
     * 如果member不是有序集key的成员,返回bulk-string-reply: nil。
     */
    public Long zrevrank(String key, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrank(key, member);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + (member) +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 根据指定的index返回,返回sorted set的成员列表
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回存储在有序集合key中的指定范围的元素。 返回的元素可以认为是按得分从最低到最高排列。 如果得分相同,将按字典排序。
     * 当你需要元素从最高分到最低分排列时,请参阅ZREVRANGE(相同的得分将使用字典倒序排序)。
     * 参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。
     * 它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。
     * start和stop都是全包含的区间,因此例如ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。
     * 超出范围的索引不会产生错误。 如果start参数的值大于有序集合中的最大索引,或者start > stop,将会返回一个空列表。
     * 如果stop的值大于有序集合的末尾,Redis会将其视为有序集合的最后一个元素。
     * 可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。这样,返回的列表将包含value1,score1,...,valueN,scoreN,而不是value1,...,valueN。
     * 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。
     */
    public Set zrangeWithScores(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeWithScores(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 在排序的设置返回的成员范围,通过索引,下令从分数高到低
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.
     * 返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。
     * 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
     */
    public Set zrevrangeWithScores(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeWithScores(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 获取成员在排序设置相关的比分
     * 起始版本:1.2.0
     * 时间复杂度:O(1)
     * 返回有序集key中,成员member的score值。
     * 如果member元素不是有序集key的成员,或key不存在,返回nil。
     */
    public Double zscore(String key, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zscore(key, member);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + member +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 对队列、集合、有序集合排序
     * 起始版本:1.0.0
     * 时间复杂度:O(N+M*log(M)) where N is the number of elements in the list or set to sort, and M the number of returned elements. When the elements are not sorted, complexity is currently O(N) as there is a copy step that will be
     * avoided in next releases.
     * 返回或存储key的list、 set 或sorted set 中的元素。默认是按照数值类型排序的,并且按照两个元素的双精度浮点数类型值进行比较。下面是SORT的最简形式:
     * SORT mylist
     * 假设mylist是一个数字列表,这条命令将返回一个元素从小到大排序的相同大小列表。如果想从大到小排序,可以使用 !DESC 修饰符。
     * SORT mylist DESC
     * 当 mylist 包含的是字符串值并且需要按照字典顺序排序,可以使用 ALPHA 修饰符:
     * SORT mylist ALPHA
     * 假设正确地设置了环境变量 !LC_COLLATE ,Redis可以感知UTF-8编码。
     * 返回元素的数量可以通过 LIMIT 修饰符限制。此修饰符有一个 offset 参数,指定了跳过的元素数量;还带有一个 count 参数,指定了从 offset 开始返回的元素数量。下面的例子将会返回排序后的列表 mylist 从第0个元素(offset 是从0开始的)开始的10个元素:
     * SORT mylist LIMIT 0 10
     * 几乎所有的修饰符可以一起使用。下述例子将返回按字典顺序降序排序后的前5个元素:
     * SORT mylist LIMIT 0 5 ALPHA DESC
     * 通过外部key排序
     * 有时我们需要使用外部的key作为权重来排序,而不是使用列表、集合或有序集合中实际的元素值。假设列表 mylist包含元素1、 2 和 3,分别代表了存储在object_1、object_2 和 object_3中的对象的唯一ID。当这些对象关联到存储在weight_1、 weight_2 和 weight_3 中的权重后, SORT 命令就能使用这些权重按照下述语句来对 mylist 排序:
     * SORT mylist BY weight_*
     * BY 选项带有一个模式(此例中的 weight_* ),用于生成用于排序的 Key 。这些key的名称指向首次与列表(本例中的1、 2 和 3)中元素的实际值出现 *
     * 跳过排序的元素
     * BY 选项可以是一个并不存在的key,这会导致 SORT 命令跳过排序操作。这在我们获取未经排序的外部key(参考下文的 GET 选项)时非常有用。
     * SORT mylist BY nosort
     * 获取外部key
     * 前面的例子仅仅是返回排序后的ID。在某些情况下,获取实际的对象而不是他们的ID更加重要(object_1、object_2 和 object_3)。获取存储在一个列表、集合或者有序集合中的key可以使用以下命令:
     * SORT mylist BY weight_* GET object_*
     * GET 选项可多次使用,以便获取每一个原始列表、集合或有序集合中元素的key。
     * 还可以通过使用特殊 # 模式获取 GET 元素本身:
     * SORT mylist BY weight_* GET object_* GET #
     * 保存排序操作的结果
     * 默认的,SORT 命令返回排序后的元素给客户端。使用 STORE 选项,可以将结果存储于一个特定的列表中,以代替返回到客户端。
     * SORT mylist BY weight_* STORE resultkey
     * SORT ... STORE的一种有趣应用模式,是联合 EXPIRE 超时命令返回key,以便在应用中可以缓存SORT操作的返回结果。 其他客户端将会使用已缓存的列表,代替每个请求的 SORT 调用。当key即将过期时,一个更新版本的缓存将会通过 SORT ... STORE 再次创建。
     * 注意,为了正确实现这种模式,很重要的一点是防止多个客户端同时重建缓存。 此时需要使用一些锁(具体的使用 SETNX)。
     * 在 BY 和 GET中使用hash
     * 可以在hash的属性上按下述语法使用 BY 和 GET 选项:
     * SORT mylist BY weight_*->fieldname GET object_*->fieldname
     * 字符串 -> 用于区分key名称和哈希属性的名称。key被替换为上面所记录的,结果key中存储的hash用于获取特定hash的属性。
     */
    public List sort(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sort(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 对队列、集合、有序集合排序
     * 起始版本:1.0.0
     * 时间复杂度:O(N+M*log(M)) where N is the number of elements in the list or set to sort, and M the number of returned elements. When the elements are not sorted, complexity is currently O(N) as there is a copy step that will be
     * avoided in next releases.
     * 返回或存储key的list、 set 或sorted set 中的元素。默认是按照数值类型排序的,并且按照两个元素的双精度浮点数类型值进行比较。下面是SORT的最简形式:
     * SORT mylist
     * 假设mylist是一个数字列表,这条命令将返回一个元素从小到大排序的相同大小列表。如果想从大到小排序,可以使用 !DESC 修饰符。
     * SORT mylist DESC
     * 当 mylist 包含的是字符串值并且需要按照字典顺序排序,可以使用 ALPHA 修饰符:
     * SORT mylist ALPHA
     * 假设正确地设置了环境变量 !LC_COLLATE ,Redis可以感知UTF-8编码。
     * 返回元素的数量可以通过 LIMIT 修饰符限制。此修饰符有一个 offset 参数,指定了跳过的元素数量;还带有一个 count 参数,指定了从 offset 开始返回的元素数量。下面的例子将会返回排序后的列表 mylist 从第0个元素(offset 是从0开始的)开始的10个元素:
     * SORT mylist LIMIT 0 10
     * 几乎所有的修饰符可以一起使用。下述例子将返回按字典顺序降序排序后的前5个元素:
     * SORT mylist LIMIT 0 5 ALPHA DESC
     * 通过外部key排序
     * 有时我们需要使用外部的key作为权重来排序,而不是使用列表、集合或有序集合中实际的元素值。假设列表 mylist包含元素1、 2 和 3,分别代表了存储在object_1、object_2 和 object_3中的对象的唯一ID。当这些对象关联到存储在weight_1、 weight_2 和 weight_3 中的权重后, SORT 命令就能使用这些权重按照下述语句来对 mylist 排序:
     * SORT mylist BY weight_*
     * BY 选项带有一个模式(此例中的 weight_* ),用于生成用于排序的 Key 。这些key的名称指向首次与列表(本例中的1、 2 和 3)中元素的实际值出现 *
     * 跳过排序的元素
     * BY 选项可以是一个并不存在的key,这会导致 SORT 命令跳过排序操作。这在我们获取未经排序的外部key(参考下文的 GET 选项)时非常有用。
     * SORT mylist BY nosort
     * 获取外部key
     * 前面的例子仅仅是返回排序后的ID。在某些情况下,获取实际的对象而不是他们的ID更加重要(object_1、object_2 和 object_3)。获取存储在一个列表、集合或者有序集合中的key可以使用以下命令:
     * SORT mylist BY weight_* GET object_*
     * GET 选项可多次使用,以便获取每一个原始列表、集合或有序集合中元素的key。
     * 还可以通过使用特殊 # 模式获取 GET 元素本身:
     * SORT mylist BY weight_* GET object_* GET #
     * 保存排序操作的结果
     * 默认的,SORT 命令返回排序后的元素给客户端。使用 STORE 选项,可以将结果存储于一个特定的列表中,以代替返回到客户端。
     * SORT mylist BY weight_* STORE resultkey
     * SORT ... STORE的一种有趣应用模式,是联合 EXPIRE 超时命令返回key,以便在应用中可以缓存SORT操作的返回结果。 其他客户端将会使用已缓存的列表,代替每个请求的 SORT 调用。当key即将过期时,一个更新版本的缓存将会通过 SORT ... STORE 再次创建。
     * 注意,为了正确实现这种模式,很重要的一点是防止多个客户端同时重建缓存。 此时需要使用一些锁(具体的使用 SETNX)。
     * 在 BY 和 GET中使用hash
     * 可以在hash的属性上按下述语法使用 BY 和 GET 选项:
     * SORT mylist BY weight_*->fieldname GET object_*->fieldname
     * 字符串 -> 用于区分key名称和哈希属性的名称。key被替换为上面所记录的,结果key中存储的hash用于获取特定hash的属性。
     */
    public List sort(String key, SortingParams sortingParameters) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sort(key, sortingParameters);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":sortingParameters:" + sortingParameters +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }


    /**
     * 返回分数范围内的成员数量
     * 起始版本:2.0.0
     * 时间复杂度:O(log(N)) with N being the number of elements in the sorted set.
     * 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。 关于参数min和max的详细使用方法,请参考ZRANGEBYSCORE命令。
     * Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see ZRANK) to get an idea of the range. Because of this there is no need to do a work proportional to the size of the range.
     */
    public Long zcount(String key, double min, double max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zcount(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回分数范围内的成员数量
     * 起始版本:2.0.0
     * 时间复杂度:O(log(N)) with N being the number of elements in the sorted set.
     * 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。 关于参数min和max的详细使用方法,请参考ZRANGEBYSCORE命令。
     * Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see ZRANK) to get an idea of the range. Because of this there is no need to do a work proportional to the size of the range.
     */
    public Long zcount(String key, String min, String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zcount(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScore(String key, double min, double max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScore(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScore(String key, double max, double min) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScore(key, max, min);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":max:" + max +
                        ":min:" + min +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScore(String key, double min, double max, int offset, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScore(key, min, max, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScore(String key, double max, double min, int offset, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScore(key, max, min, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScoreWithScores(String key, double min, double max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScoreWithScores(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScoreWithScores(String key, double max, double min) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScoreWithScores(key, max, min);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScoreWithScores(String key, double min, double max, int offset,
                                              int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScoreWithScores(key, min, max, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScoreWithScores(String key, double max, double min, int offset,
                                                 int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScoreWithScores(key, max, min, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScore(String key, String min, String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScore(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScore(String key, String max, String min) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScore(key, max, min);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScore(String key, String min, String max, int offset, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScore(key, min, max, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScore(String key, String max, String min, int offset, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScore(key, max, min, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScoreWithScores(String key, String min, String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScoreWithScores(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScoreWithScores(String key, String max, String min) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScoreWithScores(key, max, min);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由低到高排序。
     * 起始版本:1.0.5
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * 如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
     * 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
     * 具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
     * 可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
     * 可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
     * ##区间及无限
     * min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
     * 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
     * 举个例子:
     * ZRANGEBYSCORE zset (1 5
     * 返回所有符合条件1 < score <= 5的成员;
     * ZRANGEBYSCORE zset (5 (10
     * 返回所有符合条件5 < score < 10 的成员。
     */
    public Set zrangeByScoreWithScores(String key, String min, String max, int offset,
                                              int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByScoreWithScores(key, min, max, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * 起始版本:2.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYSCORE 返回有序集合中指定分数区间内的成员,分数由高到低排序。
     * ZREVRANGEBYSCORE key max min WITHSCORES LIMIT offset count
     * key	是	有序集合键名称
     * max	是	最大分数值,可使用"+inf"代替
     * min	是	最小分数值,可使用"-inf"代替
     * WITHSCORES	否	将成员分数一并返回
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * "max" 和 "min"参数前可以加 "(" 符号作为开头表示小于, "(" 符号与成员之间不能有空格
     * 可以使用 "+inf" 和 "-inf" 表示得分最大值和最小值
     * "max" 和 "min" 不能反, "max" 放后面 "min"放前面会导致返回结果为空
     * 计算成员之间的成员数量不加 "(" 符号时,参数 "min" 和 "max" 的位置也计算在内。
     * ZREVRANGEBYSCORE集合中按得分从高到底排序,所以"max"在前面,"min"在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"在前面,"max"在后面。
     */
    public Set zrevrangeByScoreWithScores(String key, String max, String min, int offset,
                                                 int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByScoreWithScores(key, max, min, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 在排序设置的所有成员在给定的索引中删除
     * 起始版本:2.0.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.
     * 移除有序集key中,指定排名(rank)区间内的所有成员。
     * 下标参数start和stop都以0为底,0处是分数最小的那个元素。
     * 这些索引也可是负数,表示位移从最高分处开始数。
     * 例如,-1是分数最高的元素,-2是分数第二高的,依次类推。
     */
    public Long zremrangeByRank(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zremrangeByRank(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除一个排序的设置在给定的分数所有成员
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.
     * 移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。
     * 自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。
     */
    public Long zremrangeByScore(String key, double start, double end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zremrangeByScore(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除一个排序的设置在给定的分数所有成员
     * 起始版本:1.2.0
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.
     * 移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。
     * 自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。
     */
    public Long zremrangeByScore(String key, String start, String end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zremrangeByScore(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回成员之间的成员数量
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)) with N being the number of elements in the sorted set.
     * ZLEXCOUNT 命令用于计算有序集合中指定成员之间的成员数量。
     * zlexcount zset [member1 [member5
     * key	是	有序集合键名称
     * min	是	在有序集合中分数排名较小的成员
     * max	是	在有序集合中分数排名较大的成员
     * 成员名称前需要加 [ 符号作为开头, [ 符号与成员之间不能有空格
     * 可以使用 - 和 + 表示得分最小值和最大值
     * min 和 max 不能反, max 放前面 min放后面会导致返回结果为0
     * 计算成员之间的成员数量时,参数 min 和 max 的位置也计算在内。
     * min 和 max 参数的含义与 zrangebylex 命令中所描述的相同
     */
    public Long zlexcount(String key, final String min, final String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zlexcount(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回指定成员区间内的成员,按字典正序排列, 分数必须相同。
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZRANGEBYLEX 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同。 在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行排序时,可以使用Redis中SortSet这种数据结构来处理。
     * ZRANGEBYLEX key min max [LIMIT offset count]
     * key	是	有序集合键名称
     * min	是	字典中排序位置较小的成员,必须以"["开头,或者以"("开头,可使用"-"代替
     * max	是	字典中排序位置较大的成员,必须以"["开头,或者以"("开头,可使用"+"代替
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * 分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
     * 成员字符串作为二进制数组的字节数进行比较。
     * 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
     * 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “min” 和 “max” 。
     * “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
     * 可以使用 “-“ 和 “+” 表示得分最小值和最大值
     * “min” 和 “max” 不能反, “max” 放前面 “min”放后面会导致返回结果为空
     * 与ZRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
     * 源码中采用C语言中 memcmp() 函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
     */
    public Set zrangeByLex(String key, final String min, final String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByLex(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回指定成员区间内的成员,按字典正序排列, 分数必须相同。
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZRANGEBYLEX 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同。 在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行排序时,可以使用Redis中SortSet这种数据结构来处理。
     * ZRANGEBYLEX key min max [LIMIT offset count]
     * key	是	有序集合键名称
     * min	是	字典中排序位置较小的成员,必须以"["开头,或者以"("开头,可使用"-"代替
     * max	是	字典中排序位置较大的成员,必须以"["开头,或者以"("开头,可使用"+"代替
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * 分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
     * 成员字符串作为二进制数组的字节数进行比较。
     * 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
     * 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “min” 和 “max” 。
     * “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
     * 可以使用 “-“ 和 “+” 表示得分最小值和最大值
     * “min” 和 “max” 不能反, “max” 放前面 “min”放后面会导致返回结果为空
     * 与ZRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
     * 源码中采用C语言中 memcmp() 函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
     */
    public Set zrangeByLex(String key, final String min, final String max,
                                   final int offset, final int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrangeByLex(key, min, max, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回指定成员区间内的成员,按字典倒序排列, 分数必须相同
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYLEX 返回指定成员区间内的成员,按成员字典倒序排序, 分数必须相同。
     * 在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行倒序排列时,可以使用Redis中SortSet这种数据结构来处理。
     * ZREVRANGEBYLEX key max min [LIMIT offset count]
     * key	是	有序集合键名称
     * max	是	字典中排序位置较大的成员,必须以"["开头,或者以"("开头,可使用"+"代替
     * min	是	字典中排序位置较小的成员,必须以"["开头,或者以"("开头,可使用"-"代替
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * 分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
     * 成员字符串作为二进制数组的字节数进行比较。
     * 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
     * 源码中采用C语言中 memcmp() 函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠前。
     * 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
     * “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
     * 可以使用 “-“ 和 “+” 表示得分最小值和最大值
     * “max”和 “min” 不能反, “max” 放后面 “min”放前面会导致返回结果为空
     * 与ZREVRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
     */
    public Set zrevrangeByLex(String key, String max, String min) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByLex(key, max, min);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 返回指定成员区间内的成员,按字典倒序排列, 分数必须相同
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).
     * ZREVRANGEBYLEX 返回指定成员区间内的成员,按成员字典倒序排序, 分数必须相同。
     * 在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行倒序排列时,可以使用Redis中SortSet这种数据结构来处理。
     * ZREVRANGEBYLEX key max min [LIMIT offset count]
     * key	是	有序集合键名称
     * max	是	字典中排序位置较大的成员,必须以"["开头,或者以"("开头,可使用"+"代替
     * min	是	字典中排序位置较小的成员,必须以"["开头,或者以"("开头,可使用"-"代替
     * LIMIT	否	返回结果是否分页,指令中包含LIMIT后offset、count必须输入
     * offset	否	返回结果起始位置
     * count	否	返回结果数量
     * 分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
     * 成员字符串作为二进制数组的字节数进行比较。
     * 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
     * 源码中采用C语言中 memcmp() 函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠前。
     * 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
     * “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
     * 可以使用 “-“ 和 “+” 表示得分最小值和最大值
     * “max”和 “min” 不能反, “max” 放后面 “min”放前面会导致返回结果为空
     * 与ZREVRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
     */
    public Set zrevrangeByLex(String key, String max, String min, int offset, int count) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Set result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zrevrangeByLex(key, max, min, offset, count);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":offset:" + offset +
                        ":count:" + count +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 删除名称按字典由低到高排序成员之间所有成员。
     * 起始版本:2.8.9
     * 时间复杂度:O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.
     * ZREMRANGEBYLEX 删除名称按字典由低到高排序成员之间所有成员。
     * 不要在成员分数不同的有序集合中使用此命令, 因为它是基于分数一致的有序集合设计的,如果使用,会导致删除的结果不正确。
     * 待删除的有序集合中,分数最好相同,否则删除结果会不正常。
     * ZREMRANGEBYLEX key min max
     * key	是	有序集合键名称
     * min	是	字典中排序位置较小的成员,必须以"["开头,或者以"("开头,可使用"-"代替
     * max	是	字典中排序位置较大的成员,必须以"["开头,或者以"("开头,可使用"+"代替
     * 提示:
     * 有序集合中分数必须相同! 如果有序集合中的成员分数有不一致的,结果就不准。
     * 成员顺序是按成员字符串作为二进制数组的字节数进行比较。
     * 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
     * 源码中采用C语言中 memcmp() 函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
     * 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
     * “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
     * 可以使用 “-“ 和 “+” 表示得分最小值和最大值
     * “max”和 “min” 不能反, “max” 放后面 “min”放前面会删除不了元素
     */
    public Long zremrangeByLex(String key, final String min, final String max) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zremrangeByLex(key, min, max);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":min:" + min +
                        ":max:" + max +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 在列表中的另一个元素之前或之后插入一个元素
     * 起始版本:2.2.0
     * 时间复杂度:O(N)
     * where N is the number of elements to traverse before seeing the value pivot.
     * This means that inserting somewhere on the left end on the list (head) can be considered O(1) and inserting somewhere on the right end (tail) is O(N).
     * 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。
     * 当 key 不存在时,这个list会被看作是空list,任何操作都不会发生。
     * 当 key 存在,但保存的不是一个list的时候,会返回error。
     */
    public Long linsert(String key, BinaryClient.LIST_POSITION where, String pivot, String value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.linsert(key, where, pivot, value);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":where:" + where +
                        ":pivot:" + pivot +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 在列表中的另一个元素之前或之后插入一个元素
     * 起始版本:2.2.0
     * 时间复杂度:O(N)
     * where N is the number of elements to traverse before seeing the value pivot.
     * This means that inserting somewhere on the left end on the list (head) can be considered O(1) and inserting somewhere on the right end (tail) is O(N).
     * 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。
     * 当 key 不存在时,这个list会被看作是空list,任何操作都不会发生。
     * 当 key 存在,但保存的不是一个list的时候,会返回error。
     */
    public Long linsert(String key, BinaryClient.LIST_POSITION where, String pivot, String value, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.linsert(key, where, pivot, value);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":where:" + where +
                        ":pivot:" + pivot +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 统计字符串指定起始位置的字节数
     * 起始版本:2.6.0
     * 时间复杂度:O(N)
     * 统计字符串被设置为1的bit数.
     * 一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
     * start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
     * 不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
     */
    public Long bitcount(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.bitcount(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 统计字符串指定起始位置的字节数
     * 起始版本:2.6.0
     * 时间复杂度:O(N)
     * 统计字符串被设置为1的bit数.
     * 一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
     * start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
     * 不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
     */
    public Long bitcount(String key, long start, long end) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.bitcount(key, start, end);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":start:" + start +
                        ":end:" + end +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Find first bit set or clear in a string
     * 起始版本:2.8.7
     * 时间复杂度:O(N)
     * 返回字符串里面第一个被设置为1或者0的bit位。
     * 返回一个位置,把字符串当做一个从左到右的字节数组,第一个符合条件的在位置0,其次在位置8,等等。
     * GETBIT 和 SETBIT 相似的也是操作字节位的命令。
     * 默认情况下整个字符串都会被检索一次,只有在指定start和end参数(指定start和end位是可行的),该范围被解释为一个字节的范围,而不是一系列的位。所以start=0 并且 end=2是指前三个字节范围内查找。
     * 注意,返回的位的位置始终是从0开始的,即使使用了start来指定了一个开始字节也是这样。
     * 和GETRANGE命令一样,start和end也可以包含负值,负值将从字符串的末尾开始计算,-1是字符串的最后一个字节,-2是倒数第二个,等等。
     * 不存在的key将会被当做空字符串来处理。
     */
    public Long bitpos(String key, boolean value) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.bitpos(key, value);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":value:" + value +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * Find first bit set or clear in a string
     * 起始版本:2.8.7
     * 时间复杂度:O(N)
     * 返回字符串里面第一个被设置为1或者0的bit位。
     * 返回一个位置,把字符串当做一个从左到右的字节数组,第一个符合条件的在位置0,其次在位置8,等等。
     * GETBIT 和 SETBIT 相似的也是操作字节位的命令。
     * 默认情况下整个字符串都会被检索一次,只有在指定start和end参数(指定start和end位是可行的),该范围被解释为一个字节的范围,而不是一系列的位。所以start=0 并且 end=2是指前三个字节范围内查找。
     * 注意,返回的位的位置始终是从0开始的,即使使用了start来指定了一个开始字节也是这样。
     * 和GETRANGE命令一样,start和end也可以包含负值,负值将从字符串的末尾开始计算,-1是字符串的最后一个字节,-2是倒数第二个,等等。
     * 不存在的key将会被当做空字符串来处理。
     */
    public Long bitpos(String key, boolean value, BitPosParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.bitpos(key, value, params);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":value:" + value +
                        ":params:" + params +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代hash里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考 SCAN命令, HSCAN与之类似 。
     */
    @Deprecated
    public ScanResult> hscan(String key, int cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult> result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    @Deprecated
    public ScanResult sscan(String key, int cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    @Deprecated
    public ScanResult zscan(String key, int cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代hash里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考 SCAN命令, HSCAN与之类似 。
     */
    public ScanResult> hscan(String key, final String cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult> result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代hash里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考 SCAN命令, HSCAN与之类似 。
     */
    public ScanResult> hscan(String key, String cursor, ScanParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult> result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.hscan(key, cursor, params);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":params:" + params +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    public ScanResult sscan(String key, final String cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    public ScanResult sscan(String key, String cursor, ScanParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.sscan(key, cursor, params);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":params:" + params +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    public ScanResult zscan(String key, final String cursor) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zscan(key, cursor);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 迭代sorted sets里面的元素
     * 起始版本:2.8.0
     * 时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..
     * 请参考SCAN
     */
    public ScanResult zscan(String key, String cursor, ScanParams params) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        ScanResult result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.zscan(key, cursor, params);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":cursor:" + cursor +
                        ":params:" + params +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 起始版本:2.8.9
     * 时间复杂度:O(1) to add every element.
     * 将除了第一个参数以外的参数存储到以第一个参数为变量名的HyperLogLog结构中.
     * 这个命令的一个副作用是它可能会更改这个HyperLogLog的内部来反映在每添加一个唯一的对象时估计的基数(集合的基数).
     * 如果一个HyperLogLog的估计的近似基数在执行命令过程中发了变化, PFADD 返回1,否则返回0,如果指定的key不存在,这个命令会自动创建一个空的HyperLogLog结构(指定长度和编码的字符串).
     * 如果在调用该命令时仅提供变量名而不指定元素也是可以的,如果这个变量名存在,则不会有任何操作,如果不存在,则会创建一个数据结构(返回1).
     * 了解更多HyperLogLog数据结构,请查阅PFCOUNT命令页面.
     */
    public Long pfadd(String key, String... elements) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.pfadd(key, elements);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":elements:" + elements +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 起始版本:2.8.9
     * 时间复杂度:O(1) to add every element.
     * 将除了第一个参数以外的参数存储到以第一个参数为变量名的HyperLogLog结构中.
     * 这个命令的一个副作用是它可能会更改这个HyperLogLog的内部来反映在每添加一个唯一的对象时估计的基数(集合的基数).
     * 如果一个HyperLogLog的估计的近似基数在执行命令过程中发了变化, PFADD 返回1,否则返回0,如果指定的key不存在,这个命令会自动创建一个空的HyperLogLog结构(指定长度和编码的字符串).
     * 如果在调用该命令时仅提供变量名而不指定元素也是可以的,如果这个变量名存在,则不会有任何操作,如果不存在,则会创建一个数据结构(返回1).
     * 了解更多HyperLogLog数据结构,请查阅PFCOUNT命令页面.
     */
    public Long pfadd(String key, Integer expireSeconds, String... elements) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.pfadd(key, elements);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":elements:" + elements +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 起始版本:2.8.9
     * 时间复杂度:O(1) with every small average constant times when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.
     * 当参数为一个key时,返回存储在HyperLogLog结构体的该变量的近似基数,如果该变量不存在,则返回0.
     * 当参数为多个key时,返回这些HyperLogLog并集的近似基数,这个值是将所给定的所有key的HyperLoglog结构合并到一个临时的HyperLogLog结构中计算而得到的.
     * HyperLogLog可以使用固定且很少的内存(每个HyperLogLog结构需要12K字节再加上key本身的几个字节)来存储集合的唯一元素.
     * 返回的可见集合基数并不是精确值, 而是一个带有 0.81% 标准错误(standard error)的近似值.
     * 例如为了记录一天会执行多少次各不相同的搜索查询, 一个程序可以在每次执行搜索查询时调用一次PFADD, 并通过调用PFCOUNT命令来获取这个记录的近似结果.
     * 注意: 这个命令的一个副作用是可能会导致HyperLogLog内部被更改,出于缓存的目的,它会用8字节的来记录最近一次计算得到基数,所以PFCOUNT命令在技术上是个写命令.
     */
    public Long pfcount(String key) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.pfcount(key);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。
     * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
     * 这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
     * 该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。
     * 这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。
     * 具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:
     * 有效的经度从-180度到180度。
     * 有效的纬度从-85.05112878度到85.05112878度。
     * 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
     */
    public Long geoadd(String key, double longitude, double latitude, String member) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geoadd(key, longitude, latitude, member);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":longitude:" + longitude +
                        ":latitude:" + latitude +
                        ":member:" + member +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。
     * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
     * 这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
     * 该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。
     * 这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。
     * 具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:
     * 有效的经度从-180度到180度。
     * 有效的纬度从-85.05112878度到85.05112878度。
     * 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
     */
    public Long geoadd(String key, double longitude, double latitude, String member, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geoadd(key, longitude, latitude, member);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":longitude:" + longitude +
                        ":latitude:" + latitude +
                        ":member:" + member +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。
     * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
     * 这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
     * 该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。
     * 这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。
     * 具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:
     * 有效的经度从-180度到180度。
     * 有效的纬度从-85.05112878度到85.05112878度。
     * 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
     */
    public Long geoadd(String key, Map memberCoordinateMap) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geoadd(key, memberCoordinateMap);
            jedis.expire(key, CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + CacheKeyCommon.CACHESERVICE_REDIS_DEFAULT_EXPIRED_SECONDS +
                        ":memberCoordinateMap:" + memberCoordinateMap +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。
     * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
     * 这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
     * 该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。
     * 这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。
     * 具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:
     * 有效的经度从-180度到180度。
     * 有效的纬度从-85.05112878度到85.05112878度。
     * 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
     */
    public Long geoadd(String key, Map memberCoordinateMap, Integer expireSeconds) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Long result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geoadd(key, memberCoordinateMap);
            if (expireSeconds > 0) {
                jedis.expire(key, expireSeconds);
            }
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":exipireSeconds:" + expireSeconds+
                        ":memberCoordinateMap:" + memberCoordinateMap +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(log(N))
     * 返回两个给定位置之间的距离。
     * 如果两个位置之间的其中一个不存在, 那么命令返回空值。
     * 指定单位的参数 unit 必须是以下单位的其中一个:
     * m 表示单位为米。
     * km 表示单位为千米。
     * mi 表示单位为英里。
     * ft 表示单位为英尺。
     * 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。
     * GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
     */
    public Double geodist(String key, String member1, String member2) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geodist(key, member1, member2);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member1:" + member1 +
                        ":member2:" + member2 +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(log(N))
     * 返回两个给定位置之间的距离。
     * 如果两个位置之间的其中一个不存在, 那么命令返回空值。
     * 指定单位的参数 unit 必须是以下单位的其中一个:
     * m 表示单位为米。
     * km 表示单位为千米。
     * mi 表示单位为英里。
     * ft 表示单位为英尺。
     * 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。
     * GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。
     */
    public Double geodist(String key, String member1, String member2, GeoUnit unit) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        Double result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geodist(key, member1, member2, unit);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member1:" + member1 +
                        ":member2:" + member2 +
                        ":unit:" + unit +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(log(N)) for each member requested, where N is the number of elements in the sorted set.
     * 返回一个或多个位置元素的 Geohash 表示。
     * 通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。
     * 由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。
     * 此命令返回一个标准的Geohash,在维基百科和geohash.org网站都有相关描述
     */
    public List geohash(String key, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geohash(key, members);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":members:" + members +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(log(N)) for each member requested, where N is the number of elements in the sorted set.
     * 从key里返回所有给定位置元素的位置(经度和纬度)。
     * 给定一个sorted set表示的空间索引,密集使用 geoadd 命令,它以获得指定成员的坐标往往是有益的。
     * 当空间索引填充通过 geoadd 的坐标转换成一个52位Geohash,所以返回的坐标可能不完全以添加元素的,但小的错误可能会出台。
     * 因为 GEOPOS 命令接受可变数量的位置元素作为输入, 所以即使用户只给定了一个位置元素, 命令也会返回数组回复。
     */
    public List geopos(String key, String... members) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.geopos(key, members);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":members:" + members +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.
     * 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
     * 范围可以使用以下其中一个单位:
     * m 表示单位为米。
     * km 表示单位为千米。
     * mi 表示单位为英里。
     * ft 表示单位为英尺。
     * 在给定以下可选项时, 命令会返回额外的信息:
     * WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
     * WITHCOORD: 将位置元素的经度和维度也一并返回。
     * WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
     * 命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:
     * ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
     * DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。
     * 在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。
     * 虽然用户可以使用 COUNT  选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时,
     * 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。
     * 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。
     */
    public List georadius(String key, double longitude, double latitude,
                                             double radius, GeoUnit unit) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.georadius(key, longitude, latitude, radius, unit);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":longitude:" + longitude +
                        ":latitude:" + latitude +
                        ":radius:" + radius +
                        ":unit:" + unit +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 时间复杂度:O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.
     * 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
     * 范围可以使用以下其中一个单位:
     * m 表示单位为米。
     * km 表示单位为千米。
     * mi 表示单位为英里。
     * ft 表示单位为英尺。
     * 在给定以下可选项时, 命令会返回额外的信息:
     * WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
     * WITHCOORD: 将位置元素的经度和维度也一并返回。
     * WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
     * 命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:
     * ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。
     * DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。
     * 在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。
     * 虽然用户可以使用 COUNT  选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时,
     * 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。
     * 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。
     */
    public List georadius(String key, double longitude, double latitude,
                                             double radius, GeoUnit unit, GeoRadiusParam param) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.georadius(key, longitude, latitude, radius, unit, param);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":longitude:" + longitude +
                        ":latitude:" + latitude +
                        ":radius:" + radius +
                        ":unit:" + unit +
                        ":param:" + param +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素,
     * 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的,
     * 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点
     * 指定成员的位置被用作查询的中心。
     */
    public List georadiusByMember(String key, String member, double radius,
                                                     GeoUnit unit) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.georadiusByMember(key, member, radius, unit);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + member +
                        ":radius:" + radius +
                        ":unit:" + unit +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 这个命令和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素,
     * 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的,
     * 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点
     * 指定成员的位置被用作查询的中心。
     */
    public List georadiusByMember(String key, String member, double radius,
                                                     GeoUnit unit, GeoRadiusParam param) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.georadiusByMember(key, member, radius, unit, param);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":member:" + member +
                        ":radius:" + radius +
                        ":unit:" + unit +
                        ":param:" + param +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 起始版本:3.2.0
     * 时间复杂度:O(1) for each subcommand specified
     * 本命令会把Redis字符串当作位数组,并能对变长位宽和任意未字节对齐的指定整型位域进行寻址。
     * 在实践中,可以使用该命令对一个有符号的5位整型数的1234位设置指定值,也可以对一个31位无符号整型数的4567位进行取值。
     * 类似地,在对指定的整数进行自增和自减操作,本命令可以提供有保证的、可配置的上溢和下溢处理操作。
     * BITFIELD命令能操作多字节位域,它会执行一系列操作,并返回一个响应数组,在参数列表中每个响应数组匹配相应的操作。
     */
    public List bitfield(String key, String... arguments) {
        ShardedJedis jedis = null;
        key = redisKeyPrefix + CacheKeyCommon.CACHESERVICE_KEY_SEPERATOR + key;
        Long timeBefore = Calendar.getInstance().getTimeInMillis();
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        List result = null;
        try {
            jedis = shardedJedisPool.getResource();
            result = jedis.bitfield(key, arguments);
            return result;
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                Long timeCost = Calendar.getInstance().getTimeInMillis() - timeBefore;
                logger.info("\n%%%%%%%%%%%%%%%%%%%%%%%%\nCacheService:" +
                        methodName + "()" +
                        ":key:" + key +
                        ":arguments:" + arguments +
                        ":result:" + result +
                        ":costTime:" + timeCost +
                        "ms" + "\n%%%%%%%%%%%%%%%%%%%%%%%%\n");
                jedis.close();
            }
        }
        return null;
    }

    /*取出@CacheFectchLater的缓存,反序列化一个value并返回结果*/
    public Object getClassMethodValue(String className, String methodName, Object[] argumentsValues) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return getValue("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore));
    }

    /*更新@CacheFectchLater的缓存,序列化一个value并存入redis,默认过期时间是一周*/
    public boolean setClassMethodValue(String className, String methodName, Object[] argumentsValues, Object value) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return setValue("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore), value);
    }

    /*更新@CacheFectchLater的缓存,序列化一个value并存入redis,并设置过期时间*/
    public boolean setClassMethodValue(String className, String methodName, Object[] argumentsValues, Object value, int expireSeconds) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return setValue("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore), value, expireSeconds);
    }

    /*更新@CacheFectchLater的缓存,序列化一个value并存入redis,默认过期时间是一周*/
    public boolean setClassMethodValue(String className, String methodName, Object argumentsValue, Object value) {
        Object[] argumentsValues = {argumentsValue};
        return setClassMethodValue(className, methodName, argumentsValues, value);
    }

    /*更新@CacheFectchLater的缓存,序列化一个value并存入redis,并设置过期时间*/
    public boolean setClassMethodValue(String className, String methodName, Object argumentsValue, Object value, int expireSeconds) {
        Object[] argumentsValues = {argumentsValue};
        return setClassMethodValue(className, methodName, argumentsValues, value, expireSeconds);
    }

    /*删除@CacheFectchLater*/
    public Long removeClassMethodValue(String className, String methodName, Object[] argumentsValues) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return del("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore));
    }

    /*过期@CacheFectchLater*/
    public Long expireClassMethodValue(String className, String methodName, Object[] argumentsValues, int expireSeconds) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return expire("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore), expireSeconds);
    }

    /*返回剩余时间。如果是-1则表示是永久@CacheFectchLater*/
    public Long ttlClassMethodValue(String className, String methodName, Object[] argumentsValues) {
        String cacheKeyBefore = "";
        cacheKeyBefore = CacheAopUtil.getCacheKeyBeforeFromArgumentsValue(argumentsValues, cacheKeyBefore);
        return ttl("cachekey:" + CachePasswordUtil.sha256(className + ":" + methodName + ":" + cacheKeyBefore));
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy