redis驅動-jedis實現1

snail_bi發表於2020-10-04
/**
 * The type Jedis client.
 *
 * @author wangsiyu
 * @date 2019.10.22
 */
@Slf4j
@Component
public class JedisClient {

    /**
     * The constant SIMPLE_CLASS_OBJ.
     */
    private static final List<Class<?>> SIMPLE_CLASS_OBJ = Lists.newArrayList();


    /**
     * LOCK_SUCCESS
     */
    private static final String LOCK_SUCCESS = "OK";

    /**
     * SET_IF_NOT_EXIST
     */
    private static final String SET_IF_NOT_EXIST = "NX";

    /**
     * SET_WITH_EXPIRE_TIME
     */
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /**
     * RELEASE_SUCCESS
     */
    private static final Long RELEASE_SUCCESS = 1L;

    static {
        SIMPLE_CLASS_OBJ.add(Number.class);
        SIMPLE_CLASS_OBJ.add(String.class);
        SIMPLE_CLASS_OBJ.add(Boolean.class);
    }

    /**
     * The Jedis pool.
     */
    @Resource
    private JedisPool jedisPool;

    /**
     * The Redis db index.
     */
    @Setter
    private Integer redisDbIndex;

    /**
     * Is simple obj boolean.
     *
     * @param classObj the class obj
     * @return the boolean
     */
    private static boolean isSimpleObj(Class<?> classObj) {
        for (Class<?> c : SIMPLE_CLASS_OBJ) {
            if (c.isAssignableFrom(classObj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 嘗試獲取鎖並設定有效時間 @param lock the lock
     *
     * @param lock    lock
     * @param expired the expired
     * @return the boolean
     */
    public Boolean acquireLock(final String lock, final int expired){
        final Object result = runTask(new Callback() {
            @Override
            public Boolean onTask(Jedis jedis) {
                jedis.select(redisDbIndex);
                long value = System.currentTimeMillis() + expired + 1;
                long acquired = jedis.setnx(lock, String.valueOf(value));
                if (acquired == 1) {
                    jedis.expire(lock, expired);
                    return true;
                }
                return false;
            }

        });
        return (Boolean)result;
    }

    /**
     * 釋放鎖資源 @param lock the lock
     *
     * @param lock lock
     */
    public void releaseLock(final String lock){
        runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(redisDbIndex);
                long currentTime = System.currentTimeMillis();
                if (currentTime < Long.valueOf(jedis.get(lock))){
                    jedis.del(lock);
                }
                return null;
            }
        });
    }

    /**
     * Set boolean.
     *
     * @param key     the key
     * @param seconds the seconds
     * @param value   the value
     * @return the boolean
     */
    public boolean set(final String key, final int seconds, final Object value) {
        return set(redisDbIndex, key, seconds, value);
    }

    /**
     * Set boolean.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param value   the value
     * @return the boolean
     */
    public boolean set(final int dbIndex, final String key, final int seconds, final Object value) {
        if (key == null || value == null) {
            return false;
        }
        Object succeed = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                String ret;
                if (isSimpleObj(value.getClass())) {
                    if (seconds == CacheTime.CACHE_EXP_FOREVER) {
                        ret = jedis.set(key, value.toString());
                    } else {
                        ret = jedis.setex(key, seconds, value.toString());
                    }
                } else {
                    byte[] bKey = SafeEncoder.encode(key);
                    byte[] bValue = serialize(value);

                    if (seconds == CacheTime.CACHE_EXP_FOREVER) {
                        ret = jedis.set(bKey, bValue);
                    } else {
                        ret = jedis.setex(bKey, seconds, bValue);
                    }
                }
                return "OK".equals(ret);
            }
        });
        return succeed != null && (boolean) succeed;
    }

    /**
     * 設定一個hash物件
     *
     * @param key     雜湊表中的key
     * @param seconds the seconds
     * @param field   域
     * @param value   值
     * @return 如果是第一次建立 ,則返回true,否則為false
     */
    public boolean setHash(final String key, final int seconds, final String field, final Object value) {
        return setHash(redisDbIndex, key, seconds, field, value);
    }

    /**
     * Sets hash.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param field   the field
     * @param value   the value
     * @return the hash
     */
    public boolean setHash(final int dbIndex, final String key, final int seconds, final String field, final Object
            value) {
        if (key == null || field == null || value == null) {
            return false;
        }
        Object succeed = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                if (isSimpleObj(value.getClass())) {
                    ret = jedis.hset(key, field, value.toString());
                } else {
                    byte[] bKey = SafeEncoder.encode(key);
                    byte[] bField = SafeEncoder.encode(field);
                    byte[] bValue = serialize(value);
                    ret = jedis.hset(bKey, bField, bValue);
                }
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret != null && ret == 1;
            }
        });
        return succeed != null && (boolean) succeed;
    }

    /**
     * Gets hash.
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param field the field
     * @param cls   the cls
     * @return the hash
     */
    public <T> T getHash(final String key, final String field, final Class<T> cls) {
        return getHash(redisDbIndex, key, field, cls);
    }

    /**
     * Gets hash.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param field   the field
     * @param cls     the cls
     * @return the hash
     */
    @SuppressWarnings("unchecked")
    public <T> T getHash(final int dbIndex, final String key, final String field, final Class<T> cls) {
        if (field == null) {
            throw new IllegalArgumentException("field can not null");
        }
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Object obj = null;
                if (isSimpleObj(cls)) {
                    String str = jedis.hget(key, field);
                    if (str != null) {
                        obj = createSimpleObj(str, cls);
                    }
                } else {
                    byte[] bs = jedis.hget(SafeEncoder.encode(key), SafeEncoder.encode(field));
                    if (bs != null) {
                        obj = deserialize(bs);
                    }
                }
                return obj;
            }
        });
        return ret == null ? null : (T) ret;
    }

    /**
     * Gets hash.
     *
     * @param <T>    the type parameter
     * @param key    the key
     * @param cls    the cls
     * @param fields the fields
     * @return the hash
     */
    public <T> List<T> getHash(final String key, final Class<T> cls, final String... fields) {
        return getHash(redisDbIndex, key, cls, fields);
    }

    /**
     * Gets hash map.
     *
     * @param <T>    the type parameter
     * @param key    the key
     * @param cls    the cls
     * @param fields the fields
     * @return the hash map
     */
    public <T> Map<String, T> getHashMap(String key, Class<T> cls, String... fields) {
        List<T> list = getHash(key, cls, fields);
        if (list == null) {
            return null;
        }
        Map<String, T> map = Maps.newHashMap();
        for (int i = 0; i < fields.length; i++) {
            map.put(fields[i], list.get(i));
        }
        return map;
    }

    /**
     * Gets hash.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param cls     the cls
     * @param fields  the fields
     * @return the hash
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> getHash(final int dbIndex, final String key, final Class<T> cls, final String... fields) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                final byte[][] bfields = new byte[fields.length][];
                for (int i = 0; i < bfields.length; i++) {
                    bfields[i] = SafeEncoder.encode(fields[i]);
                }
                List<byte[]> bytes = jedis.hmget(SafeEncoder.encode(key), bfields);
                if (bytes == null) {return null;}
                List<T> retList = Lists.newArrayList();
                boolean isSimple = isSimpleObj(cls);
                for (byte[] e : bytes) {
                    if (e == null) {
                        retList.add(null);
                        continue;
                    }
                    retList.add(isSimple ? createSimpleObj(SafeEncoder.encode(e), cls) : (T) deserialize(e));
                }
                return retList;
            }
        });
        return ret == null ? null : (List<T>) ret;
    }

    /**
     * sorted set 新增
     *
     * @param <T>     the type parameter
     * @param key     the key
     * @param seconds the seconds
     * @param score   the score
     * @param member  the member
     * @return the long
     */
    public <T> Long zadd(final String key,final int seconds,final double score, final String member) {
        return zadd(redisDbIndex, key, seconds,score, member);
    }

    /**
     * Zadd long.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param score   the score
     * @param member  the member
     * @return the long
     */
    public <T> Long zadd(final int dbIndex,final String key,final int seconds,final double score, final String member) {
        if (key == null || member == null) {
            return 0L;
        }
        Object rs = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[] bMember = SafeEncoder.encode(member);
                ret = jedis.zadd(bKey,score,bMember);
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret == null ? 0 : ret;
            }
        });
        return (Long) rs;
    }

    /**
     * 獲取有序集合成員數
     *
     * @param key the key
     * @return the long
     */
    public Long zcard(final String key) {
        return zcard(redisDbIndex,key);
    }

    /**
     * Zcard long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the long
     */
    public Long zcard(final int dbIndex, final String key) {
        if (key == null) {
            return 0L;
        }
        Object length = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                ret = jedis.zcard(bKey);
                return ret == null ? 0 : ret;
            }
        });
        return (Long) length;
    }

    /**
     * 移除有序集合中的一個成員
     *
     * @param <T> the type parameter
     * @param key the key
     * @param val the val
     * @return the long
     */
    public <T> Long zrem(final String key, final String val) {
        return zrem(redisDbIndex, key, val);
    }

    /**
     * Zrem long.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param val     the val
     * @return the long
     */
    public <T> Long zrem(final int dbIndex, final String key, final String val) {
        if (key == null || val == null) {
            return 0L;
        }
        Object rs = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[] bMember = SafeEncoder.encode(val);
                ret = jedis.zrem(bKey,bMember);
                return ret == null ? 0 : ret;
            }
        });
        return (Long) rs;
    }

    /**
     * 返回有序集合中指定分數區間的成員列表由小到大
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param start the start
     * @param end   the end
     * @return the list
     */
    public <T> List<T> zRang(final String key, final Long start, final Long end) {
        return zRang(redisDbIndex, key, start, end);
    }

    /**
     * Z rang list.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param start   the start
     * @param end     the end
     * @return the list
     */
    public <T> List<T> zRang(final int dbIndex, final String key, final Long start, final Long end) {
        if (key == null || start == null || end == null) {
            return Lists.newArrayList();
        }
        Object obj = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Set<byte[]> rbyteSet;
                byte[] bKey = SafeEncoder.encode(key);
                rbyteSet = jedis.zrange(bKey, start, end);
                List<T> retList = Lists.newArrayList();
                for (byte[] rbyte : rbyteSet) {
                    retList.add((T)SafeEncoder.encode(rbyte));
                }
                return retList;
            }
        });
        return (List<T>) obj;
    }

    /**
     * 返回有序集合中指定分數區間的成員列表有大到小
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param start the start
     * @param end   the end
     * @return the list
     */
    public <T> List<T>  zRevRANGE (final String key, final Long start, final Long end) {
        return zRevRange(redisDbIndex, key, start, end);
    }

    /**
     * Z rev range list.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param start   the start
     * @param end     the end
     * @return the list
     */
    public <T> List<T> zRevRange(final int dbIndex, final String key, final Long start, final Long end) {
        if (key == null || start == null || end == null) {
            return Lists.newArrayList();
        }
        Object obj = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Set<byte[]> rbyteSet;
                byte[] bKey = SafeEncoder.encode(key);
                rbyteSet = jedis.zrevrange(bKey, start, end);
                List<T> retList = Lists.newArrayList();
                for (byte[] rbyte : rbyteSet) {
                    retList.add((T)SafeEncoder.encode(rbyte));
                }
                return retList;
            }
        });
        return (List<T>) obj;
    }

    /**
     * Z rang by score list.
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param start the start
     * @param end   the end
     * @return the list
     */
    public <T> List<T> zRangByScore(final String key, final Double start, final Double end) {
        return zRangByScore(redisDbIndex, key, start, end);
    }

    /**
     * Z rang by score list.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param start   the start
     * @param end     the end
     * @return the list
     */
    public <T> List<T> zRangByScore(final int dbIndex, final String key, final Double start, final Double end) {
        if (key == null || start == null || end == null) {
            return Lists.newArrayList();
        }
        Object obj = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Set<byte[]> rbyteSet;
                byte[] bKey = SafeEncoder.encode(key);
                rbyteSet = jedis.zrangeByScore(bKey, start, end);
                List<T> retList = Lists.newArrayList();
                for (byte[] rbyte : rbyteSet) {
                    retList.add((T)SafeEncoder.encode(rbyte));
                }
                return retList;
            }
        });
        return (List<T>) obj;
    }

    /**
     * 獲取list的size
     *
     * @param key the key
     * @return the list size
     */
    public long getListSize(final String key) {
        return getListSize(redisDbIndex, key);
    }

    /**
     * 獲取list的size
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the list size
     */
    public long getListSize(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.llen(key);
            }
        });
        return ret == null ? 0 : (long) ret;
    }

    /**
     * 獲取list所有元素
     *
     * @param <T> the type parameter
     * @param key the key
     * @return the list range
     */
    public <T> List<T> getListRange(final String key) {
        return getListRange(redisDbIndex, key);
    }

    /**
     * 獲取list所有元素
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @return the list range
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> getListRange(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.lrange(key, 0, jedis.llen(key) - 1);
            }
        });
        return ret == null ? Collections.<T>emptyList() : (List<T>) ret;
    }

    /**
     * 獲取list所有元素
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @return the list
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> lrange(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.lrange(key, 0, -1);
            }
        });
        return ret == null ? Collections.<T>emptyList() : (List<T>) ret;
    }

    /**
     * 獲取key下面所有的值,string的
     *
     * @param <K> the type parameter
     * @param <V> the type parameter
     * @param key the key
     * @return the key all
     */
    public <K, V> Map<K, V> getKeyAll(final String key) {
        return getKeyAll(redisDbIndex, key);
    }

    /**
     * 獲取key下面所有的值,string的
     *
     * @param <K>     the type parameter
     * @param <V>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @return the key all
     */
    @SuppressWarnings("unchecked")
    public <K, V> Map<K, V> getKeyAll(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.hgetAll(key);
            }
        });
        return ret == null ? Collections.<K, V>emptyMap() : (Map<K, V>) ret;
    }

    /**
     * 獲取指定指定index的list儲存物件
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param index the index
     * @param cls   the cls
     * @return the list
     */
    public <T> T getList(final String key, final int index, final Class<T> cls) {
        return getList(redisDbIndex, key, index, cls);
    }

    /**
     * Gets list.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param index   the index
     * @param cls     the cls
     * @return the list
     */
    @SuppressWarnings("unchecked")
    public <T> T getList(final int dbIndex, final String key, final int index, final Class<T> cls) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Object obj = null;
                if (isSimpleObj(cls)) {
                    String str = jedis.lindex(key, index);
                    if (str != null) {
                        obj = createSimpleObj(str, cls);
                    }
                } else {
                    byte[] bs = jedis.lindex(SafeEncoder.encode(key), index);
                    if (bs != null) {
                        obj = deserialize(bs);
                    }
                }
                return obj;
            }
        });
        return ret == null ? null : (T) ret;
    }

    /**
     * 講一批物件推送到list中
     *
     * @param key     the key
     * @param seconds the seconds
     * @param values  the values
     * @return the boolean
     */
    public boolean pushList(final String key, final int seconds, final Object... values) {
        return pushList(redisDbIndex, key, seconds, values);
    }

    /**
     * Push list boolean.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param values  the values
     * @return the boolean
     */
    public boolean pushList(final int dbIndex, final String key, final int seconds, final Object... values) {
        if (key == null || values == null || values.length == 0) {
            return false;
        }
        Object succeed = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                if (isSimpleObj(values.getClass())) {
                    String[] array = new String[values.length];
                    for (int i = 0; i < values.length; i++) {
                        array[i] = values[i].toString();
                    }
                    ret = jedis.lpush(key, array);
                } else {
                    byte[] bKey = SafeEncoder.encode(key);
                    byte[][] array = new byte[values.length][];
                    for (int i = 0; i < values.length; i++) {
                        array[i] = serialize(values[i]);
                    }
                    ret = jedis.lpush(bKey, array);
                }
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret != null && ret == 1;
            }
        });
        return succeed != null && (boolean) succeed;

    }


    /**
     * Lpush list boolean.
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param value the value
     * @return the boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean lpushList(final String key, final T value) {
        return lpushList(redisDbIndex, key, CacheTime.CACHE_EXP_WEEK, value);
    }

    /**
     * Lpush list boolean.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param value   the value
     * @return the boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean lpushList(final int dbIndex, final String key, final T value) {
        return lpushList(dbIndex, key, CacheTime.CACHE_EXP_WEEK, value);

    }

    /**
     * Lpush list boolean.
     *
     * @param <T>     the type parameter
     * @param key     the key
     * @param seconds the seconds
     * @param values  the values
     * @return the boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean lpushList(final String key, final Integer seconds, final T... values) {
        return lpushList(redisDbIndex, key, seconds, values);
    }

    /**
     * Lpush list boolean.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param values  the values
     * @return the boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean lpushList(final int dbIndex, final String key, final Integer seconds, final T... values) {
        if (key == null || values == null || values.length == 0) {
            return false;
        }
        Object succeed = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[][] array = new byte[values.length][];
                for (int i = 0; i < values.length; i++) {
                    array[i] = serialize(values[i]);
                }
                ret = jedis.lpush(bKey, array);
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret != null && ret > 0;
            }
        });
        return succeed != null && (boolean) succeed;
    }

    /**
     * Range list list.
     *
     * @param <T>   the type parameter
     * @param key   the key
     * @param start the start
     * @param end   the end
     * @return the list
     */
    public <T> List<T> rangeList(final String key, final Long start, final Long end) {
        return rangeList(redisDbIndex, key, start, end);
    }

    /**
     * Range list list.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param start   the start
     * @param end     the end
     * @return the list
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> rangeList(final int dbIndex, final String key, final Long start, final Long end) {
        if (key == null || start == null || end == null) {
            return Lists.newArrayList();
        }
        Object obj = runTask(new Callback() {

            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                List<byte[]> rbyteList;
                byte[] bKey = SafeEncoder.encode(key);
                rbyteList = jedis.lrange(bKey, start, end);
                List<T> retList = Lists.newArrayList();
                for (byte[] rbyte : rbyteList) {
                    retList.add((T) deserialize(rbyte));
                }
                return retList;
            }
        });
        return (List<T>) obj;
    }

    /**
     * Trim list boolean.
     *
     * @param key   the key
     * @param start the start
     * @param end   the end
     * @return the boolean
     */
    public Boolean trimList(final String key, final Long start, final Long end) {
        return trimList(redisDbIndex, key, start, end);
    }

    /**
     * Trim list boolean.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param start   the start
     * @param end     the end
     * @return the boolean
     */
    public Boolean trimList(final int dbIndex, final String key, final Long start, final Long end) {
        if (key == null || start == null || end == null) {
            return Boolean.FALSE;
        }
        Object succeed = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                String ret;
                byte[] bKey = SafeEncoder.encode(key);
                ret = jedis.ltrim(bKey, start, end);
                return "OK".equals(ret);
            }
        });
        return succeed != null && (boolean) succeed;
    }

    /**
     * 對hash表中的某個元素執行增加操作,如果操作的field非數字,則結果返回null.如果是負數,就是減少
     *
     * @param key   the key
     * @param field the field
     * @param value 需要增加的值
     * @return 增加之後的值 ,如果操作的field非數字,則結果返回null
     */
    public Long incrHash(final String key, final String field, final long value) {
        return incrHash(redisDbIndex, key, field, value);
    }

    /**
     * Incr hash long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param field   the field
     * @param value   the value
     * @return the long
     */
    public Long incrHash(final int dbIndex, final String key, final String field, final long value) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.hincrBy(key, field, value);
            }
        });
        return ret == null ? null : (Long) ret;
    }

    /**
     * Incr hash double.
     *
     * @param key   the key
     * @param field the field
     * @param value the value
     * @return the double
     */
    public Double incrHash(final String key, final String field, final double value) {
        return incrHash(redisDbIndex, key, field, value);
    }

    /**
     * Incr hash double.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param field   the field
     * @param value   the value
     * @return the double
     */
    public Double incrHash(final int dbIndex, final String key, final String field, final double value) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.hincrByFloat(key, field, value);
            }
        });
        return ret == null ? null : (Double) ret;
    }

    /**
     * Get t.
     *
     * @param <T> the type parameter
     * @param key the key
     * @param cls the cls
     * @return the t
     */
    public <T> T get(final String key, final Class<T> cls) {
        return get(redisDbIndex, key, cls);
    }

    /**
     * Get t.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param cls     the cls
     * @return the t
     */
    @SuppressWarnings("unchecked")
    public <T> T get(final int dbIndex, final String key, final Class<T> cls) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Object obj = null;
                if (isSimpleObj(cls)) {
                    String str = jedis.get(key);
                    if (str != null) {
                        obj = createSimpleObj(str, cls);
                    }
                } else {
                    byte[] bs = jedis.get(SafeEncoder.encode(key));
                    if (bs != null) {
                        obj = deserialize(bs);
                    }
                }
                return obj;
            }
        });
        return ret == null ? null : (T) ret;
    }

    /**
     * Sadd ns long.
     *
     * @param <T>     the type parameter
     * @param key     the key
     * @param value   the value
     * @param seconds the seconds
     * @return the long
     */
    public <T> Long saddNS(String key,String value, final int seconds) {
        return sadd(redisDbIndex, key, seconds, value);
    }

    /**
     * Sadd ns long.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param value   the value
     * @return the long
     */
//這裡不判斷簡單型別和物件,和其他的有所不同,請注意
    public <T> Long saddNS(final int dbIndex, final String key, final int seconds, final String value) {
        if (key == null || value == null) {
            return 0L;
        }
        Object rs = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[] bValue =SafeEncoder.encode(value);
                ret = jedis.sadd(bKey, bValue);
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret == null ? 0 : ret;
            }
        });
        return (Long) rs;
    }

    /**
     * Smember set.
     *
     * @param <T> the type parameter
     * @param key the key
     * @return the set
     */
    public <T> Set<T> smember(String key) {
        return smember(redisDbIndex, key);
    }

    /**
     * Smember set.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @return the set
     */
//這裡不判斷簡單型別和物件,和其他的有所不同,請注意
    public <T> Set<T> smember(final int dbIndex, final String key) {
        if (key == null ) {
            return null;
        }
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                byte[] bKey = SafeEncoder.encode(key);
                Set<byte[]> smembers = jedis.smembers(bKey);
                Set<String> set = new HashSet<>();
                if(CollectionUtil.isNotEmpty(smembers)){
                    for(byte[] b:smembers){
                        set.add(new String(b));
                    }
                }
                return set ;
            }
        });
        return (Set<T>) ret;
    }


    /**
     * Sadd long.
     *
     * @param <T>     the type parameter
     * @param key     the key
     * @param value   the value
     * @param seconds the seconds
     * @return the long
     */
    public <T> Long sadd(String key, T value, final int seconds) {
        return sadd(redisDbIndex, key, seconds, value);
    }

    /**
     * Sadd long.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param seconds the seconds
     * @param value   the value
     * @return the long
     */
//這裡不判斷簡單型別和物件,和其他的有所不同,請注意
    public <T> Long sadd(final int dbIndex, final String key, final int seconds, final T value) {
        if (key == null || value == null) {
            return 0L;
        }
        Object rs = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[] bValue = serialize(value);
                ret = jedis.sadd(bKey, bValue);
                if (seconds != CacheTime.CACHE_EXP_FOREVER) {
                    jedis.expire(key, seconds);
                }
                return ret == null ? 0 : ret;
            }
        });
        return (Long) rs;
    }

    /**
     * Slen long.
     *
     * @param key the key
     * @return the long
     */
    public Long slen(final String key) {
        return slen(redisDbIndex, key);
    }

    /**
     * Slen long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the long
     */
    public Long slen(final int dbIndex, final String key) {
        if (key == null) {
            return 0L;
        }
        Object length = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                ret = jedis.scard(bKey);
                return ret == null ? 0 : ret;
            }
        });
        return (Long) length;
    }

    /**
     * Srem long.
     *
     * @param <T> the type parameter
     * @param key the key
     * @param val the val
     * @return the long
     */
    public <T> Long srem(final String key, final T val) {
        return srem(redisDbIndex, key, val);
    }

    /**
     * Srem long.
     *
     * @param <T>     the type parameter
     * @param dbIndex the db index
     * @param key     the key
     * @param val     the val
     * @return the long
     */
    public <T> Long srem(final int dbIndex, final String key, final T val) {
        if (key == null || val == null) {
            return 0L;
        }
        Object rs = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                Long ret;
                byte[] bKey = SafeEncoder.encode(key);
                byte[] bVal = serialize(val);
                ret = jedis.srem(bKey, bVal);
                return ret == null ? 0 : ret;
            }
        });
        return (Long) rs;
    }

    /**
     * Create simple obj t.
     *
     * @param <T> the type parameter
     * @param arg the arg
     * @param cls the cls
     * @return the t
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private <T> T createSimpleObj(String arg, Class<T> cls) {
        T ret = null;
        Constructor[] constructors = cls.getDeclaredConstructors();
        for (Constructor t : constructors) {
            Class[] parameterTypes = t.getParameterTypes();
            if (parameterTypes.length == 1 && parameterTypes[0].equals(String.class)) {
                try {
                    ret = (T) t.newInstance(arg);
                } catch (Exception e) {
                    log.error("create simple obj error: " + e.getMessage(), e);
                }
                break;
            }
        }
        return ret;
    }


    /**
     * Delete long.
     *
     * @param key the key
     * @return the long
     */
    public Long delete(final String key) {
        return delete(redisDbIndex, key);
    }

    /**
     * Delete long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the long
     */
    public Long delete(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.del(key);
            }
        });
        return ret == null ? 0L : (long) ret;
    }

    public void deleteBatch(final int dbIndex, final List<String> keys) {
        Object ret = runTask(jedis -> {
            jedis.select(dbIndex);
            Pipeline pipelined = jedis.pipelined();
            for (String key : keys) {
                pipelined.del(key);
            }
            pipelined.sync();
            return null;
        });
    }

    /**
     * Del hash field long.
     *
     * @param key   the key
     * @param field the field
     * @return the long
     */
    public Long delHashField(final String key, final String field) {
        return delHashField(redisDbIndex, key, field);
    }

    /**
     * Del hash field long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param field   the field
     * @return the long
     */
    public Long delHashField(final int dbIndex, final String key, final String field) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.hdel(key, field);
            }
        });
        return ret == null ? 0L : (long) ret;
    }


    /**
     * Incr by long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param value   the value
     * @return the long
     */
    public long incrBy(final int dbIndex, final String key, final long value) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.incrBy(key, value);
            }
        });
        return ret == null ? 0L : (long) ret;
    }

    /**
     * Decr by long.
     *
     * @param key   the key
     * @param value the value
     * @return the long
     */
    public long decrBy(final String key, final long value) {
        return decrBy(redisDbIndex, key, value);
    }

    /**
     * Decr by long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @param value   the value
     * @return the long
     */
    public long decrBy(final int dbIndex, final String key, final long value) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.incrBy(key, -value);
            }
        });
        return ret == null ? 0L : (long) ret;
    }

    /**
     * Incr long.
     *
     * @param key the key
     * @return the long
     */
//i++
    public long incr(final String key) {
        return incr(redisDbIndex, key);
    }

    /**
     * Incr long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the long
     */
    public long incr(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.incr(key);
            }
        });
        return ret == null ? 0L : (long) ret;
    }

    /**
     * Run task object.
     *
     * @param callback the callback
     * @return the object
     */
    private Object runTask(Callback callback) {
        Jedis jedis = null;
        boolean broken = false;
        try {
            jedis = jedisPool.getResource();
            return callback.onTask(jedis);
        } catch (JedisException e) {
            broken = handleJedisException(e);
        } catch (Exception e) {
            log.error("Redis runTask error: ", e);
        } finally {
            closeResource(jedis, broken);
            jedis = null;
        }
        return null;
    }

    /**
     * Serialize byte [ ].
     *
     * @param object the object
     * @return the byte [ ]
     */
    private byte[] serialize(Object object) {
        if (!(object instanceof Serializable)) {
            throw new IllegalArgumentException("設定快取的物件:" + object.getClass() + "無法序列化,確保 implements Serializable");
        }
        ObjectOutputStream objOS = null;
        ByteArrayOutputStream byteAOS = new ByteArrayOutputStream();
        try {
            objOS = new ObjectOutputStream(byteAOS);
            objOS.writeObject(object);
            return byteAOS.toByteArray();
        } catch (Exception e) {
            log.error("serialize error: " + e.getMessage());
        } finally {
            try {
                if (objOS != null) {objOS.close();}
                byteAOS.close();
            } catch (IOException e) {
                log.error("serialize close error : " + e.getMessage());
            }
        }
        return null;
    }

    /**
     * Deserialize object.
     *
     * @param bytes the bytes
     * @return the object
     */
    private Object deserialize(byte[] bytes) {
        ByteArrayInputStream byteAIS = new ByteArrayInputStream(bytes);
        ObjectInputStream objIS = null;
        try {
            objIS = new ObjectInputStream(byteAIS);
            return objIS.readObject();
        } catch (Exception e) {
            log.error("deserialize error: " + e.getMessage());
        } finally {
            try {
                byteAIS.close();
                if (objIS != null) {objIS.close();}
            } catch (IOException e) {
                log.error("deserialize close error: " + e.getMessage());
            }
        }
        return null;
    }

    /**
     * The TTL command returns the remaining time to live in seconds of a key
     * that has an {expire(String, int) EXPIRE} set. This introspection
     * capability allows a Redis client to check how many seconds a given key
     * will continue to be part of the dataset.
     *
     * @param key key
     * @return Integer reply, returns the remaining time to live in seconds of a key that has an EXPIRE. In Redis 2.6 or older, if the Key does not exists or does not have an associated expire, -1 is returned. In Redis 2.8 or newer, if the Key does not have an associated expire, -1 is returned or if the Key does not exists, -2 is returned.
     */
    public Long ttl(final String key) {
        return ttl(redisDbIndex, key);
    }

    /**
     * Ttl long.
     *
     * @param dbIndex the db index
     * @param key     the key
     * @return the long
     */
    public Long ttl(final int dbIndex, final String key) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.ttl(key);
            }
        });
        return ret == null ? 0L : (long) ret;
    }

    /**
     * Flush db string.
     *
     * @param dbIndex the db index
     * @return the string
     */
    public String flushDB(final int dbIndex) {
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.flushDB();
            }
        });
        if (ret instanceof String){
            return ret == null ? "0" : (String) ret;
        }
        return "0";
    }

    /**
     * The interface Callback.
     *
     * @author wangsiyu
     * @date 2019.10.22
     */
    interface Callback {
        /**
         * On task object.
         *
         * @param jedis the jedis
         * @return the object
         */
        Object onTask(Jedis jedis);
    }


    /**
     * Handle jedisException, write log and return whether the connection is broken.
     *
     * @param jedisException the jedis exception
     * @return the boolean
     */
    private boolean handleJedisException(JedisException jedisException) {
        if (jedisException instanceof JedisConnectionException) {
            log.error("Redis connection lost.", jedisException);
        } else if (jedisException instanceof JedisDataException) {
            if ((jedisException.getMessage() != null) && (jedisException.getMessage().indexOf("READONLY") != -1)) {
                log.error("Redis connection are read-only slave.", jedisException);
            } else {
                // dataException, isBroken=false
                return false;
            }
        } else {
            log.error("Jedis exception happen.", jedisException);
        }
        return true;
    }

    /**
     * Return jedis connection to the pool, call different return methods depends on the conectionBroken status.
     *
     * @param jedis           the jedis
     * @param conectionBroken the conection broken
     */
    private void closeResource(Jedis jedis, boolean conectionBroken) {
        try {
            if (conectionBroken) {
                jedisPool.returnBrokenResource(jedis);
            } else {
                jedisPool.returnResource(jedis);
            }
        } catch (Exception e) {
            log.error("return back jedis failed, will fore close the jedis.", e);
            jedis.close();
        }
    }

    /**
     * Keys set.
     *
     * @param patternStr the pattern str
     * @return the set
     */
    public Set<String> keys(String patternStr){
        return keys(redisDbIndex, patternStr);
    }

    /**
     * Keys set.
     *
     * @param dbIndex    the db index
     * @param patternStr the pattern str
     * @return the set
     */
    public Set<String> keys(final int dbIndex, final String patternStr){
        Object ret = runTask(new Callback() {
            @Override
            public Object onTask(Jedis jedis) {
                jedis.select(dbIndex);
                return jedis.keys(patternStr);
            }
        });
        if (ret == null){
            return Sets.newHashSet();
        }
        Set<String> result = (Set<String>) ret;
        return result;
    }

}

相關文章