001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.support.redis.jedis;
017
018import com.jfinal.log.Log;
019import io.jboot.exception.JbootIllegalConfigException;
020import io.jboot.support.redis.JbootRedisBase;
021import io.jboot.support.redis.JbootRedisConfig;
022import io.jboot.support.redis.RedisScanResult;
023import io.jboot.utils.QuietlyUtil;
024import io.jboot.utils.StrUtil;
025import redis.clients.jedis.*;
026import redis.clients.jedis.exceptions.JedisConnectionException;
027import redis.clients.jedis.params.ScanParams;
028import redis.clients.jedis.resps.ScanResult;
029
030import java.util.*;
031import java.util.Map.Entry;
032import java.util.stream.Collectors;
033
034/**
035 * 参考: com.jfinal.plugin.redis
036 * JbootRedis 命令文档: http://redisdoc.com/
037 */
038public class JbootJedisImpl extends JbootRedisBase {
039
040    protected JedisPool jedisPool;
041    protected JbootRedisConfig config;
042
043    private static final Log LOG = Log.getLog(JbootJedisImpl.class);
044
045    public JbootJedisImpl(JbootRedisConfig config) {
046        super(config);
047
048        this.config = config;
049
050        String host = config.getHost();
051        Integer port = config.getPort();
052        Integer timeout = config.getTimeout();
053        String password = config.getPassword();
054        Integer database = config.getDatabase();
055        String clientName = config.getClientName();
056
057        if (host.contains(":")) {
058            port = Integer.valueOf(host.split(":")[1]);
059        }
060
061
062        JedisPoolConfig poolConfig = new JedisPoolConfig();
063
064        if (StrUtil.isNotBlank(config.getTestWhileIdle())) {
065            poolConfig.setTestWhileIdle(config.getTestWhileIdle());
066        }
067
068        if (StrUtil.isNotBlank(config.getTestOnBorrow())) {
069            poolConfig.setTestOnBorrow(config.getTestOnBorrow());
070        }
071
072        if (StrUtil.isNotBlank(config.getTestOnCreate())) {
073            poolConfig.setTestOnCreate(config.getTestOnCreate());
074        }
075
076        if (StrUtil.isNotBlank(config.getTestOnReturn())) {
077            poolConfig.setTestOnReturn(config.getTestOnReturn());
078        }
079
080        if (StrUtil.isNotBlank(config.getMinEvictableIdleTimeMillis())) {
081            poolConfig.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
082        }
083
084        if (StrUtil.isNotBlank(config.getTimeBetweenEvictionRunsMillis())) {
085            poolConfig.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
086        }
087
088        if (StrUtil.isNotBlank(config.getNumTestsPerEvictionRun())) {
089            poolConfig.setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
090        }
091
092        if (StrUtil.isNotBlank(config.getMaxTotal())) {
093            poolConfig.setMaxTotal(config.getMaxTotal());
094        }
095
096        if (StrUtil.isNotBlank(config.getMaxIdle())) {
097            poolConfig.setMaxIdle(config.getMaxIdle());
098        }
099
100        if (StrUtil.isNotBlank(config.getMinIdle())) {
101            poolConfig.setMinIdle(config.getMinIdle());
102        }
103
104        if (StrUtil.isNotBlank(config.getMaxWaitMillis())) {
105            poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());
106        }
107
108        this.jedisPool = new JedisPool(poolConfig, host, port, timeout, timeout, password, database, clientName);
109    }
110
111
112    public JbootJedisImpl(JedisPool jedisPool) {
113        super(null);
114        this.jedisPool = jedisPool;
115    }
116
117    /**
118     * 存放 key value 对到 redis
119     * 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
120     * 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
121     */
122    @Override
123    public String set(Object key, Object value) {
124        Jedis jedis = getJedis();
125        try {
126            return jedis.set(keyToBytes(key), valueToBytes(value));
127        } finally {
128            returnResource(jedis);
129        }
130    }
131
132
133    @Override
134    public Long setnx(Object key, Object value) {
135        Jedis jedis = getJedis();
136        try {
137            return jedis.setnx(keyToBytes(key), valueToBytes(value));
138        } finally {
139            returnResource(jedis);
140        }
141    }
142
143    /**
144     * 存放 key value 对到 redis
145     * 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
146     * 此方法用了修改 incr 等的值
147     */
148    @Override
149    public String setWithoutSerialize(Object key, Object value) {
150        Jedis jedis = getJedis();
151        try {
152            return jedis.set(keyToBytes(key), value.toString().getBytes());
153        } finally {
154            returnResource(jedis);
155        }
156    }
157
158
159    /**
160     * 存放 key value 对到 redis,并将 key 的生存时间设为 seconds (以秒为单位)。
161     * 如果 key 已经存在, SETEX 命令将覆写旧值。
162     */
163    @Override
164    public String setex(Object key, int seconds, Object value) {
165        Jedis jedis = getJedis();
166        try {
167            return jedis.setex(keyToBytes(key), seconds, valueToBytes(value));
168        } finally {
169            returnResource(jedis);
170        }
171    }
172
173    /**
174     * 返回 key 所关联的 value 值
175     * 如果 key 不存在那么返回特殊值 nil 。
176     */
177    @Override
178    @SuppressWarnings("unchecked")
179    public <T> T get(Object key) {
180        Jedis jedis = getJedis();
181        try {
182            return (T) valueFromBytes(jedis.get(keyToBytes(key)));
183        } finally {
184            returnResource(jedis);
185        }
186    }
187
188    @Override
189    public String getWithoutSerialize(Object key) {
190        Jedis jedis = getJedis();
191        try {
192            byte[] bytes = jedis.get(keyToBytes(key));
193            if (bytes == null || bytes.length == 0) {
194                return null;
195            }
196            return new String(bytes);
197        } finally {
198            returnResource(jedis);
199        }
200    }
201
202
203    /**
204     * 删除给定的一个 key
205     * 不存在的 key 会被忽略。
206     */
207    @Override
208    public Long del(Object key) {
209        Jedis jedis = getJedis();
210        try {
211            return jedis.del(keyToBytes(key));
212        } finally {
213            returnResource(jedis);
214        }
215    }
216
217    /**
218     * 删除给定的多个 key
219     * 不存在的 key 会被忽略。
220     */
221    @Override
222    public Long del(Object... keys) {
223        if (keys == null || keys.length == 0) {
224            return 0L;
225        }
226        Jedis jedis = getJedis();
227        try {
228            return jedis.del(keysToBytesArray(keys));
229        } finally {
230            returnResource(jedis);
231        }
232    }
233
234    /**
235     * 查找所有符合给定模式 pattern 的 key 。
236     * KEYS * 匹配数据库中所有 key 。
237     * KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
238     * KEYS h*llo 匹配 hllo 和 heeeeello 等。
239     * KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
240     * 特殊符号用 \ 隔开
241     */
242    @Override
243    public Set<String> keys(String pattern) {
244        Jedis jedis = getJedis();
245        try {
246            return jedis.keys(pattern);
247        } finally {
248            returnResource(jedis);
249        }
250    }
251
252    /**
253     * 同时设置一个或多个 key-value 对。
254     * 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
255     * MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
256     * <pre>
257     * 例子:
258     * Cache cache = RedisKit.use();                    // 使用 JbootRedis 的 cache
259     * cache.mset("k1", "v1", "k2", "v2");              // 放入多个 key value 键值对
260     * List list = cache.mget("k1", "k2");              // 利用多个键值得到上面代码放入的值
261     * </pre>
262     */
263    @Override
264    public String mset(Object... keysValues) {
265        if (keysValues.length % 2 != 0) {
266            throw new IllegalArgumentException("wrong number of arguments for met, keysValues length can not be odd");
267        }
268        Jedis jedis = getJedis();
269        try {
270            byte[][] kv = new byte[keysValues.length][];
271            for (int i = 0; i < keysValues.length; i++) {
272                if (i % 2 == 0) {
273                    kv[i] = keyToBytes(keysValues[i]);
274                } else {
275                    kv[i] = valueToBytes(keysValues[i]);
276                }
277            }
278            return jedis.mset(kv);
279        } finally {
280            returnResource(jedis);
281        }
282    }
283
284    /**
285     * 返回所有(一个或多个)给定 key 的值。
286     * 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
287     */
288    @Override
289    @SuppressWarnings("rawtypes")
290    public List mget(Object... keys) {
291        Jedis jedis = getJedis();
292        try {
293            byte[][] keysBytesArray = keysToBytesArray(keys);
294            List<byte[]> data = jedis.mget(keysBytesArray);
295            return valueListFromBytesList(data);
296        } finally {
297            returnResource(jedis);
298        }
299    }
300
301    /**
302     * 将 key 中储存的数字值减一。
303     * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
304     * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
305     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
306     * 关于递增(increment) / 递减(decrement)操作的更多信息,请参见 INCR 命令。
307     */
308    @Override
309    public Long decr(Object key) {
310        Jedis jedis = getJedis();
311        try {
312            return jedis.decr(keyToBytes(key));
313        } finally {
314            returnResource(jedis);
315        }
316    }
317
318    /**
319     * 将 key 所储存的值减去减量 decrement 。
320     * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。
321     * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
322     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
323     * 关于更多递增(increment) / 递减(decrement)操作的更多信息,请参见 INCR 命令。
324     */
325    @Override
326    public Long decrBy(Object key, long longValue) {
327        Jedis jedis = getJedis();
328        try {
329            return jedis.decrBy(keyToBytes(key), longValue);
330        } finally {
331            returnResource(jedis);
332        }
333    }
334
335    /**
336     * 将 key 中储存的数字值增一。
337     * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
338     * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
339     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
340     */
341    @Override
342    public Long incr(Object key) {
343        Jedis jedis = getJedis();
344        try {
345            return jedis.incr(keyToBytes(key));
346        } finally {
347            returnResource(jedis);
348        }
349    }
350
351    /**
352     * 将 key 所储存的值加上增量 increment 。
353     * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。
354     * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
355     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
356     * 关于递增(increment) / 递减(decrement)操作的更多信息,参见 INCR 命令。
357     */
358    @Override
359    public Long incrBy(Object key, long longValue) {
360        Jedis jedis = getJedis();
361        try {
362            return jedis.incrBy(keyToBytes(key), longValue);
363        } finally {
364            returnResource(jedis);
365        }
366    }
367
368    /**
369     * 检查给定 key 是否存在。
370     */
371    @Override
372    public boolean exists(Object key) {
373        Jedis jedis = getJedis();
374        try {
375            return jedis.exists(keyToBytes(key));
376        } finally {
377            returnResource(jedis);
378        }
379    }
380
381    /**
382     * 从当前数据库中随机返回(不删除)一个 key 。
383     */
384    @Override
385    public String randomKey() {
386        Jedis jedis = getJedis();
387        try {
388            return jedis.randomKey();
389        } finally {
390            returnResource(jedis);
391        }
392    }
393
394    /**
395     * 将 key 改名为 newkey 。
396     * 当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
397     * 当 newkey 已经存在时, RENAME 命令将覆盖旧值。
398     */
399    @Override
400    public String rename(Object oldkey, Object newkey) {
401        Jedis jedis = getJedis();
402        try {
403            return jedis.rename(keyToBytes(oldkey), keyToBytes(newkey));
404        } finally {
405            returnResource(jedis);
406        }
407    }
408
409    /**
410     * 将当前数据库的 key 移动到给定的数据库 db 当中。
411     * 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。
412     * 因此,也可以利用这一特性,将 MOVE 当作锁(locking)原语(primitive)。
413     */
414    @Override
415    public Long move(Object key, int dbIndex) {
416        Jedis jedis = getJedis();
417        try {
418            return jedis.move(keyToBytes(key), dbIndex);
419        } finally {
420            returnResource(jedis);
421        }
422    }
423
424    /**
425     * 将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除。
426     */
427    @Override
428    public String migrate(String host, int port, Object key, int destinationDb, int timeout) {
429        Jedis jedis = getJedis();
430        try {
431            return jedis.migrate(host, port, keyToBytes(key), destinationDb, timeout);
432        } finally {
433            returnResource(jedis);
434        }
435    }
436
437    /**
438     * 切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。
439     * 默认使用 0 号数据库。
440     * 注意:在 Jedis 对象被关闭时,数据库又会重新被设置为初始值,所以本方法 select(...)
441     * 正常工作需要使用如下方式之一:
442     * 1:使用 RedisInterceptor,在本线程内共享同一个 Jedis 对象
443     * 2:使用 JbootRedis.call(ICallback) 进行操作
444     * 3:自行获取 Jedis 对象进行操作
445     */
446    @Override
447    public String select(int databaseIndex) {
448        Jedis jedis = getJedis();
449        try {
450            return jedis.select(databaseIndex);
451        } finally {
452            returnResource(jedis);
453        }
454    }
455
456    /**
457     * 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
458     * 在 JbootRedis 中,带有生存时间的 key 被称为『易失的』(volatile)。
459     */
460    @Override
461    public Long expire(Object key, int seconds) {
462        Jedis jedis = getJedis();
463        try {
464            return jedis.expire(keyToBytes(key), seconds);
465        } finally {
466            returnResource(jedis);
467        }
468    }
469
470    /**
471     * EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
472     */
473    @Override
474    public Long expireAt(Object key, long unixTime) {
475        Jedis jedis = getJedis();
476        try {
477            return jedis.expireAt(keyToBytes(key), unixTime);
478        } finally {
479            returnResource(jedis);
480        }
481    }
482
483    /**
484     * 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
485     */
486    @Override
487    public Long pexpire(Object key, long milliseconds) {
488        Jedis jedis = getJedis();
489        try {
490            return jedis.pexpire(keyToBytes(key), milliseconds);
491        } finally {
492            returnResource(jedis);
493        }
494    }
495
496    /**
497     * 这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位。
498     */
499    @Override
500    public Long pexpireAt(Object key, long millisecondsTimestamp) {
501        Jedis jedis = getJedis();
502        try {
503            return jedis.pexpireAt(keyToBytes(key), millisecondsTimestamp);
504        } finally {
505            returnResource(jedis);
506        }
507    }
508
509    /**
510     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
511     * 当 key 存在但不是字符串类型时,返回一个错误。
512     */
513    @Override
514    @SuppressWarnings("unchecked")
515    public <T> T getSet(Object key, Object value) {
516        Jedis jedis = getJedis();
517        try {
518            return (T) valueFromBytes(jedis.getSet(keyToBytes(key), valueToBytes(value)));
519        } finally {
520            returnResource(jedis);
521        }
522    }
523
524    /**
525     * 移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
526     */
527    @Override
528    public Long persist(Object key) {
529        Jedis jedis = getJedis();
530        try {
531            return jedis.persist(keyToBytes(key));
532        } finally {
533            returnResource(jedis);
534        }
535    }
536
537    /**
538     * 返回 key 所储存的值的类型。
539     */
540    @Override
541    public String type(Object key) {
542        Jedis jedis = getJedis();
543        try {
544            return jedis.type(keyToBytes(key));
545        } finally {
546            returnResource(jedis);
547        }
548    }
549
550    /**
551     * 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
552     */
553    @Override
554    public Long ttl(Object key) {
555        Jedis jedis = getJedis();
556        try {
557            return jedis.ttl(keyToBytes(key));
558        } finally {
559            returnResource(jedis);
560        }
561    }
562
563    /**
564     * 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
565     */
566    @Override
567    public Long pttl(Object key) {
568        Jedis jedis = getJedis();
569        try {
570            return jedis.pttl(keyToBytes(key));
571        } finally {
572            returnResource(jedis);
573        }
574    }
575
576    /**
577     * 对象被引用的数量
578     */
579    @Override
580    public Long objectRefcount(Object key) {
581        Jedis jedis = getJedis();
582        try {
583            return jedis.objectRefcount(keyToBytes(key));
584        } finally {
585            returnResource(jedis);
586        }
587    }
588
589    /**
590     * 对象没有被访问的空闲时间
591     */
592    @Override
593    public Long objectIdletime(Object key) {
594        Jedis jedis = getJedis();
595        try {
596            return jedis.objectIdletime(keyToBytes(key));
597        } finally {
598            returnResource(jedis);
599        }
600    }
601
602    /**
603     * 将哈希表 key 中的域 field 的值设为 value 。
604     * 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
605     * 如果域 field 已经存在于哈希表中,旧值将被覆盖。
606     */
607    @Override
608    public Long hset(Object key, Object field, Object value) {
609        Jedis jedis = getJedis();
610        try {
611            return jedis.hset(keyToBytes(key), valueToBytes(field), valueToBytes(value));
612        } finally {
613            returnResource(jedis);
614        }
615    }
616
617    /**
618     * 同时将多个 field-value (域-值)对设置到哈希表 key 中。
619     * 此命令会覆盖哈希表中已存在的域。
620     * 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
621     */
622    @Override
623    public String hmset(Object key, Map<Object, Object> hash) {
624        Jedis jedis = getJedis();
625        try {
626            Map<byte[], byte[]> para = new HashMap<byte[], byte[]>();
627            for (Entry<Object, Object> e : hash.entrySet())
628                para.put(valueToBytes(e.getKey()), valueToBytes(e.getValue()));
629            return jedis.hmset(keyToBytes(key), para);
630        } finally {
631            returnResource(jedis);
632        }
633    }
634
635    /**
636     * 返回哈希表 key 中给定域 field 的值。
637     */
638    @Override
639    @SuppressWarnings("unchecked")
640    public <T> T hget(Object key, Object field) {
641        Jedis jedis = getJedis();
642        try {
643            return (T) valueFromBytes(jedis.hget(keyToBytes(key), valueToBytes(field)));
644        } finally {
645            returnResource(jedis);
646        }
647    }
648
649    /**
650     * 返回哈希表 key 中,一个或多个给定域的值。
651     * 如果给定的域不存在于哈希表,那么返回一个 nil 值。
652     * 因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
653     */
654    @Override
655    @SuppressWarnings("rawtypes")
656    public List hmget(Object key, Object... fields) {
657        Jedis jedis = getJedis();
658        try {
659            List<byte[]> data = jedis.hmget(keyToBytes(key), valuesToBytesArray(fields));
660            return valueListFromBytesList(data);
661        } finally {
662            returnResource(jedis);
663        }
664    }
665
666    /**
667     * 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
668     */
669    @Override
670    public Long hdel(Object key, Object... fields) {
671        Jedis jedis = getJedis();
672        try {
673            return jedis.hdel(keyToBytes(key), valuesToBytesArray(fields));
674        } finally {
675            returnResource(jedis);
676        }
677    }
678
679    /**
680     * 查看哈希表 key 中,给定域 field 是否存在。
681     */
682    @Override
683    public boolean hexists(Object key, Object field) {
684        Jedis jedis = getJedis();
685        try {
686            return jedis.hexists(keyToBytes(key), valueToBytes(field));
687        } finally {
688            returnResource(jedis);
689        }
690    }
691
692    /**
693     * 返回哈希表 key 中,所有的域和值。
694     * 在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
695     */
696    @Override
697    @SuppressWarnings("rawtypes")
698    public Map hgetAll(Object key) {
699        Jedis jedis = getJedis();
700        try {
701            Map<byte[], byte[]> data = jedis.hgetAll(keyToBytes(key));
702            Map<Object, Object> result = new HashMap<Object, Object>();
703            for (Entry<byte[], byte[]> e : data.entrySet())
704                result.put(valueFromBytes(e.getKey()), valueFromBytes(e.getValue()));
705            return result;
706        } finally {
707            returnResource(jedis);
708        }
709    }
710
711    /**
712     * 返回哈希表 key 中所有域的值。
713     */
714    @Override
715    @SuppressWarnings("rawtypes")
716    public List hvals(Object key) {
717        Jedis jedis = getJedis();
718        try {
719            List<byte[]> data = jedis.hvals(keyToBytes(key));
720            return valueListFromBytesList(data);
721        } finally {
722            returnResource(jedis);
723        }
724    }
725
726    /**
727     * 返回哈希表 key 中的所有域。
728     * 底层实现此方法取名为 hfields 更为合适,在此仅为与底层保持一致
729     */
730    @Override
731    public Set<Object> hkeys(Object key) {
732        Jedis jedis = getJedis();
733        try {
734            Set<byte[]> fieldSet = jedis.hkeys(keyToBytes(key));
735            Set<Object> result = new HashSet<Object>();
736            fieldSetFromBytesSet(fieldSet, result);
737            return result;
738        } finally {
739            returnResource(jedis);
740        }
741    }
742
743    /**
744     * 返回哈希表 key 中域的数量。
745     */
746    @Override
747    public Long hlen(Object key) {
748        Jedis jedis = getJedis();
749        try {
750            return jedis.hlen(keyToBytes(key));
751        } finally {
752            returnResource(jedis);
753        }
754    }
755
756    /**
757     * 为哈希表 key 中的域 field 的值加上增量 increment 。
758     * 增量也可以为负数,相当于对给定域进行减法操作。
759     * 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。
760     * 如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。
761     * 对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。
762     * 本操作的值被限制在 64 位(bit)有符号数字表示之内。
763     */
764    @Override
765    public Long hincrBy(Object key, Object field, long value) {
766        Jedis jedis = getJedis();
767        try {
768            return jedis.hincrBy(keyToBytes(key), valueToBytes(field), value);
769        } finally {
770            returnResource(jedis);
771        }
772    }
773
774    /**
775     * 为哈希表 key 中的域 field 加上浮点数增量 increment 。
776     * 如果哈希表中没有域 field ,那么 HINCRBYFLOAT 会先将域 field 的值设为 0 ,然后再执行加法操作。
777     * 如果键 key 不存在,那么 HINCRBYFLOAT 会先创建一个哈希表,再创建域 field ,最后再执行加法操作。
778     * 当以下任意一个条件发生时,返回一个错误:
779     * 1:域 field 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
780     * 2:域 field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)
781     * HINCRBYFLOAT 命令的详细功能和 INCRBYFLOAT 命令类似,请查看 INCRBYFLOAT 命令获取更多相关信息。
782     */
783    @Override
784    public Double hincrByFloat(Object key, Object field, double value) {
785        Jedis jedis = getJedis();
786        try {
787            return jedis.hincrByFloat(keyToBytes(key), valueToBytes(field), value);
788        } finally {
789            returnResource(jedis);
790        }
791    }
792
793    /**
794     * 返回列表 key 中,下标为 index 的元素。
795     * 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
796     * 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
797     * 如果 key 不是列表类型,返回一个错误。
798     */
799    @SuppressWarnings("unchecked")
800
801    /**
802     * 返回列表 key 中,下标为 index 的元素。
803     * 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,
804     * 以 1 表示列表的第二个元素,以此类推。
805     * 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
806     * 如果 key 不是列表类型,返回一个错误。
807     */
808    @Override
809    public <T> T lindex(Object key, long index) {
810        Jedis jedis = getJedis();
811        try {
812            return (T) valueFromBytes(jedis.lindex(keyToBytes(key), index));
813        } finally {
814            returnResource(jedis);
815        }
816    }
817
818
819    /**
820     * 返回列表 key 的长度。
821     * 如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
822     * 如果 key 不是列表类型,返回一个错误。
823     */
824    @Override
825    public Long llen(Object key) {
826        Jedis jedis = getJedis();
827        try {
828            return jedis.llen(keyToBytes(key));
829        } finally {
830            returnResource(jedis);
831        }
832    }
833
834    /**
835     * 移除并返回列表 key 的头元素。
836     */
837    @Override
838    @SuppressWarnings("unchecked")
839    public <T> T lpop(Object key) {
840        Jedis jedis = getJedis();
841        try {
842            return (T) valueFromBytes(jedis.lpop(keyToBytes(key)));
843        } finally {
844            returnResource(jedis);
845        }
846    }
847
848    /**
849     * 将一个或多个值 value 插入到列表 key 的表头
850     * 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,
851     * 对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,
852     * 这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
853     * 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
854     * 当 key 存在但不是列表类型时,返回一个错误。
855     */
856    @Override
857    public Long lpush(Object key, Object... values) {
858        Jedis jedis = getJedis();
859        try {
860            return jedis.lpush(keyToBytes(key), valuesToBytesArray(values));
861        } finally {
862            returnResource(jedis);
863        }
864    }
865
866    /**
867     * 将列表 key 下标为 index 的元素的值设置为 value 。
868     * 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
869     * 关于列表下标的更多信息,请参考 LINDEX 命令。
870     */
871    @Override
872    public String lset(Object key, long index, Object value) {
873        Jedis jedis = getJedis();
874        try {
875            return jedis.lset(keyToBytes(key), index, valueToBytes(value));
876        } finally {
877            returnResource(jedis);
878        }
879    }
880
881    /**
882     * 根据参数 count 的值,移除列表中与参数 value 相等的元素。
883     * count 的值可以是以下几种:
884     * count 大于 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
885     * count 小于 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
886     * count 等于 0 : 移除表中所有与 value 相等的值。
887     */
888    @Override
889    public Long lrem(Object key, long count, Object value) {
890        Jedis jedis = getJedis();
891        try {
892            return jedis.lrem(keyToBytes(key), count, valueToBytes(value));
893        } finally {
894            returnResource(jedis);
895        }
896    }
897
898    /**
899     * 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
900     * 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
901     * 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
902     * <pre>
903     * 例子:
904     * 获取 list 中所有数据:cache.lrange(listKey, 0, -1);
905     * 获取 list 中下标 1 到 3 的数据: cache.lrange(listKey, 1, 3);
906     * </pre>
907     */
908    @Override
909    @SuppressWarnings("rawtypes")
910    public List lrange(Object key, long start, long end) {
911        Jedis jedis = getJedis();
912        try {
913            List<byte[]> data = jedis.lrange(keyToBytes(key), start, end);
914            if (data != null) {
915                return valueListFromBytesList(data);
916            } else {
917                return new ArrayList<byte[]>(0);
918            }
919        } finally {
920            returnResource(jedis);
921        }
922    }
923
924    /**
925     * 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
926     * 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
927     * 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
928     * 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
929     * 当 key 不是列表类型时,返回一个错误。
930     */
931    @Override
932    public String ltrim(Object key, long start, long end) {
933        Jedis jedis = getJedis();
934        try {
935            return jedis.ltrim(keyToBytes(key), start, end);
936        } finally {
937            returnResource(jedis);
938        }
939    }
940
941    /**
942     * 移除并返回列表 key 的尾元素。
943     */
944    @Override
945    @SuppressWarnings("unchecked")
946    public <T> T rpop(Object key) {
947        Jedis jedis = getJedis();
948        try {
949            return (T) valueFromBytes(jedis.rpop(keyToBytes(key)));
950        } finally {
951            returnResource(jedis);
952        }
953    }
954
955    /**
956     * 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
957     * 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
958     * 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
959     */
960    @Override
961    @SuppressWarnings("unchecked")
962    public <T> T rpoplpush(Object srcKey, Object dstKey) {
963        Jedis jedis = getJedis();
964        try {
965            return (T) valueFromBytes(jedis.rpoplpush(keyToBytes(srcKey), keyToBytes(dstKey)));
966        } finally {
967            returnResource(jedis);
968        }
969    }
970
971    /**
972     * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
973     * 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如
974     * 对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,
975     * 等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
976     * 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。
977     * 当 key 存在但不是列表类型时,返回一个错误。
978     */
979    @Override
980    public Long rpush(Object key, Object... values) {
981        Jedis jedis = getJedis();
982        try {
983            return jedis.rpush(keyToBytes(key), valuesToBytesArray(values));
984        } finally {
985            returnResource(jedis);
986        }
987    }
988
989    /**
990     * BLPOP 是列表的阻塞式(blocking)弹出原语。
991     * 它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
992     * 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
993     */
994    @Override
995    @SuppressWarnings("rawtypes")
996    public List blpop(Object... keys) {
997        Jedis jedis = getJedis();
998        try {
999            List<byte[]> data = jedis.blpop(this.config.getTimeout(),keysToBytesArray(keys));
1000            return keyValueListFromBytesList(data);
1001        } finally {
1002            returnResource(jedis);
1003        }
1004    }
1005
1006    /**
1007     * BLPOP 是列表的阻塞式(blocking)弹出原语。
1008     * 它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
1009     * 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
1010     */
1011    @Override
1012    @SuppressWarnings("rawtypes")
1013    public List blpop(Integer timeout, Object... keys) {
1014        Jedis jedis = getJedis();
1015        try {
1016
1017            //这里注意:第一个为key,第二个为value
1018            List<byte[]> data = jedis.blpop(timeout, keysToBytesArray(keys));
1019            return keyValueListFromBytesList(data);
1020        } finally {
1021            returnResource(jedis);
1022        }
1023    }
1024
1025    /**
1026     * BRPOP 是列表的阻塞式(blocking)弹出原语。
1027     * 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
1028     * 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。
1029     * 关于阻塞操作的更多信息,请查看 BLPOP 命令, BRPOP 除了弹出元素的位置和 BLPOP 不同之外,其他表现一致。
1030     */
1031    @Override
1032    @SuppressWarnings("rawtypes")
1033    public List brpop(Object... keys) {
1034        Jedis jedis = getJedis();
1035        try {
1036            List<byte[]> data = jedis.brpop(this.config.getTimeout(),keysToBytesArray(keys));
1037            return keyValueListFromBytesList(data);
1038        } finally {
1039            returnResource(jedis);
1040        }
1041    }
1042
1043    /**
1044     * BRPOP 是列表的阻塞式(blocking)弹出原语。
1045     * 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
1046     * 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。
1047     * 关于阻塞操作的更多信息,请查看 BLPOP 命令, BRPOP 除了弹出元素的位置和 BLPOP 不同之外,其他表现一致。
1048     */
1049    @Override
1050    @SuppressWarnings("rawtypes")
1051    public List brpop(Integer timeout, Object... keys) {
1052        Jedis jedis = getJedis();
1053        try {
1054            List<byte[]> data = jedis.brpop(timeout, keysToBytesArray(keys));
1055            return keyValueListFromBytesList(data);
1056        } finally {
1057            returnResource(jedis);
1058        }
1059    }
1060
1061    /**
1062     * 使用客户端向 JbootRedis 服务器发送一个 PING ,如果服务器运作正常的话,会返回一个 PONG 。
1063     * 通常用于测试与服务器的连接是否仍然生效,或者用于测量延迟值。
1064     */
1065    @Override
1066    public String ping() {
1067        Jedis jedis = getJedis();
1068        try {
1069            return jedis.ping();
1070        } finally {
1071            returnResource(jedis);
1072        }
1073    }
1074
1075    /**
1076     * 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
1077     * 假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
1078     * 当 key 不是集合类型时,返回一个错误。
1079     */
1080    @Override
1081    public Long sadd(Object key, Object... members) {
1082        Jedis jedis = getJedis();
1083        try {
1084            return jedis.sadd(keyToBytes(key), valuesToBytesArray(members));
1085        } finally {
1086            returnResource(jedis);
1087        }
1088    }
1089
1090    /**
1091     * 返回集合 key 的基数(集合中元素的数量)。
1092     */
1093    @Override
1094    public Long scard(Object key) {
1095        Jedis jedis = getJedis();
1096        try {
1097            return jedis.scard(keyToBytes(key));
1098        } finally {
1099            returnResource(jedis);
1100        }
1101    }
1102
1103    /**
1104     * 移除并返回集合中的一个随机元素。
1105     * 如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER 命令。
1106     */
1107    @Override
1108    @SuppressWarnings("unchecked")
1109    public <T> T spop(Object key) {
1110        Jedis jedis = getJedis();
1111        try {
1112            return (T) valueFromBytes(jedis.spop(keyToBytes(key)));
1113        } finally {
1114            returnResource(jedis);
1115        }
1116    }
1117
1118    /**
1119     * 返回集合 key 中的所有成员。
1120     * 不存在的 key 被视为空集合。
1121     */
1122    @Override
1123    @SuppressWarnings("rawtypes")
1124    public Set smembers(Object key) {
1125        Jedis jedis = getJedis();
1126        try {
1127            Set<byte[]> data = jedis.smembers(keyToBytes(key));
1128            Set<Object> result = new HashSet<Object>();
1129            valueSetFromBytesSet(data, result);
1130            return result;
1131        } finally {
1132            returnResource(jedis);
1133        }
1134    }
1135
1136    /**
1137     * 判断 member 元素是否集合 key 的成员。
1138     */
1139    @Override
1140    public boolean sismember(Object key, Object member) {
1141        Jedis jedis = getJedis();
1142        try {
1143            return jedis.sismember(keyToBytes(key), valueToBytes(member));
1144        } finally {
1145            returnResource(jedis);
1146        }
1147    }
1148
1149    /**
1150     * 返回多个集合的交集,多个集合由 keys 指定
1151     */
1152    @Override
1153    @SuppressWarnings("rawtypes")
1154    public Set sinter(Object... keys) {
1155        Jedis jedis = getJedis();
1156        try {
1157            Set<byte[]> data = jedis.sinter(keysToBytesArray(keys));
1158            Set<Object> result = new HashSet<Object>();
1159            valueSetFromBytesSet(data, result);
1160            return result;
1161        } finally {
1162            returnResource(jedis);
1163        }
1164    }
1165
1166    /**
1167     * 返回集合中的一个随机元素。
1168     */
1169    @Override
1170    @SuppressWarnings("unchecked")
1171    public <T> T srandmember(Object key) {
1172        Jedis jedis = getJedis();
1173        try {
1174            return (T) valueFromBytes(jedis.srandmember(keyToBytes(key)));
1175        } finally {
1176            returnResource(jedis);
1177        }
1178    }
1179
1180    /**
1181     * 返回集合中的 count 个随机元素。
1182     * 从 JbootRedis 2.6 版本开始, SRANDMEMBER 命令接受可选的 count 参数:
1183     * 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。
1184     * 如果 count 大于等于集合基数,那么返回整个集合。
1185     * 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
1186     * 该操作和 SPOP 相似,但 SPOP 将随机元素从集合中移除并返回,而 SRANDMEMBER 则仅仅返回随机元素,而不对集合进行任何改动。
1187     */
1188    @Override
1189    @SuppressWarnings("rawtypes")
1190    public List srandmember(Object key, int count) {
1191        Jedis jedis = getJedis();
1192        try {
1193            List<byte[]> data = jedis.srandmember(keyToBytes(key), count);
1194            return valueListFromBytesList(data);
1195        } finally {
1196            returnResource(jedis);
1197        }
1198    }
1199
1200    /**
1201     * 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
1202     */
1203    @Override
1204    public Long srem(Object key, Object... members) {
1205        Jedis jedis = getJedis();
1206        try {
1207            return jedis.srem(keyToBytes(key), valuesToBytesArray(members));
1208        } finally {
1209            returnResource(jedis);
1210        }
1211    }
1212
1213    /**
1214     * 返回多个集合的并集,多个集合由 keys 指定
1215     * 不存在的 key 被视为空集。
1216     */
1217    @Override
1218    @SuppressWarnings("rawtypes")
1219    public Set sunion(Object... keys) {
1220        Jedis jedis = getJedis();
1221        try {
1222            Set<byte[]> data = jedis.sunion(keysToBytesArray(keys));
1223            Set<Object> result = new HashSet<Object>();
1224            valueSetFromBytesSet(data, result);
1225            return result;
1226        } finally {
1227            returnResource(jedis);
1228        }
1229    }
1230
1231    /**
1232     * 返回一个集合的全部成员,该集合是所有给定集合之间的差集。
1233     * 不存在的 key 被视为空集。
1234     */
1235    @Override
1236    @SuppressWarnings("rawtypes")
1237    public Set sdiff(Object... keys) {
1238        Jedis jedis = getJedis();
1239        try {
1240            Set<byte[]> data = jedis.sdiff(keysToBytesArray(keys));
1241            Set<Object> result = new HashSet<Object>();
1242            valueSetFromBytesSet(data, result);
1243            return result;
1244        } finally {
1245            returnResource(jedis);
1246        }
1247    }
1248
1249    /**
1250     * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
1251     * 如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,
1252     * 并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
1253     */
1254    @Override
1255    public Long zadd(Object key, double score, Object member) {
1256        Jedis jedis = getJedis();
1257        try {
1258            return jedis.zadd(keyToBytes(key), score, valueToBytes(member));
1259        } finally {
1260            returnResource(jedis);
1261        }
1262    }
1263
1264    @Override
1265    public Long zadd(Object key, Map<Object, Double> scoreMembers) {
1266        Jedis jedis = getJedis();
1267        try {
1268            Map<byte[], Double> para = new HashMap<>();
1269            for (Entry<Object, Double> e : scoreMembers.entrySet()) {
1270                para.put(valueToBytes(e.getKey()), e.getValue());    // valueToBytes is important
1271            }
1272            return jedis.zadd(keyToBytes(key), para);
1273        } finally {
1274            returnResource(jedis);
1275        }
1276    }
1277
1278    /**
1279     * 返回有序集 key 的基数。
1280     */
1281    @Override
1282    public Long zcard(Object key) {
1283        Jedis jedis = getJedis();
1284        try {
1285            return jedis.zcard(keyToBytes(key));
1286        } finally {
1287            returnResource(jedis);
1288        }
1289    }
1290
1291    /**
1292     * 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。
1293     * 关于参数 min 和 max 的详细使用方法,请参考 ZRANGEBYSCORE 命令。
1294     */
1295    @Override
1296    public Long zcount(Object key, double min, double max) {
1297        Jedis jedis = getJedis();
1298        try {
1299            return jedis.zcount(keyToBytes(key), min, max);
1300        } finally {
1301            returnResource(jedis);
1302        }
1303    }
1304
1305    /**
1306     * 为有序集 key 的成员 member 的 score 值加上增量 increment 。
1307     */
1308    @Override
1309    public Double zincrby(Object key, double score, Object member) {
1310        Jedis jedis = getJedis();
1311        try {
1312            return jedis.zincrby(keyToBytes(key), score, valueToBytes(member));
1313        } finally {
1314            returnResource(jedis);
1315        }
1316    }
1317
1318    /**
1319     * 返回有序集 key 中,指定区间内的成员。
1320     * 其中成员的位置按 score 值递增(从小到大)来排序。
1321     * 具有相同 score 值的成员按字典序(lexicographical order )来排列。
1322     * 如果你需要成员按 score 值递减(从大到小)来排列,请使用 ZREVRANGE 命令。
1323     */
1324    @Override
1325    @SuppressWarnings("rawtypes")
1326    public List zrange(Object key, long start, long end) {
1327        Jedis jedis = getJedis();
1328        try {
1329            List<byte[]> data = jedis.zrange(keyToBytes(key), start, end);
1330            List<Object> result = data.stream().map(d->valueFromBytes(d)).collect(Collectors.toList());    // 有序集合必须 LinkedHashSet
1331            return result;
1332        } finally {
1333            returnResource(jedis);
1334        }
1335    }
1336
1337    /**
1338     * 返回有序集 key 中,指定区间内的成员。
1339     * 其中成员的位置按 score 值递减(从大到小)来排列。
1340     * 具有相同 score 值的成员按字典序的逆序(reverse lexicographical order)排列。
1341     * 除了成员按 score 值递减的次序排列这一点外, ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。
1342     */
1343    @Override
1344    @SuppressWarnings("rawtypes")
1345    public List zrevrange(Object key, long start, long end) {
1346        Jedis jedis = getJedis();
1347        try {
1348            List<byte[]> data = jedis.zrevrange(keyToBytes(key), start, end);
1349            List<Object> result = data.stream().map(d->valueFromBytes(d)).collect(Collectors.toList());    // 有序集合必须 LinkedHashSet
1350            return result;
1351        } finally {
1352            returnResource(jedis);
1353        }
1354    }
1355
1356    /**
1357     * 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。
1358     * 有序集成员按 score 值递增(从小到大)次序排列。
1359     */
1360    @Override
1361    @SuppressWarnings("rawtypes")
1362    public List zrangeByScore(Object key, double min, double max) {
1363        Jedis jedis = getJedis();
1364        try {
1365            List<byte[]> data = jedis.zrangeByScore(keyToBytes(key), min, max);
1366            List<Object> result = data.stream().map(d->valueFromBytes(d)).collect(Collectors.toList());    // 有序集合必须 LinkedHashSet
1367            return result;
1368        } finally {
1369            returnResource(jedis);
1370        }
1371    }
1372
1373    /**
1374     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
1375     * 排名以 0 为底,也就是说, score 值最小的成员排名为 0 。
1376     * 使用 ZREVRANK 命令可以获得成员按 score 值递减(从大到小)排列的排名。
1377     */
1378    @Override
1379    public Long zrank(Object key, Object member) {
1380        Jedis jedis = getJedis();
1381        try {
1382            return jedis.zrank(keyToBytes(key), valueToBytes(member));
1383        } finally {
1384            returnResource(jedis);
1385        }
1386    }
1387
1388    /**
1389     * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
1390     * 排名以 0 为底,也就是说, score 值最大的成员排名为 0 。
1391     * 使用 ZRANK 命令可以获得成员按 score 值递增(从小到大)排列的排名。
1392     */
1393    @Override
1394    public Long zrevrank(Object key, Object member) {
1395        Jedis jedis = getJedis();
1396        try {
1397            return jedis.zrevrank(keyToBytes(key), valueToBytes(member));
1398        } finally {
1399            returnResource(jedis);
1400        }
1401    }
1402
1403    /**
1404     * 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
1405     * 当 key 存在但不是有序集类型时,返回一个错误。
1406     */
1407    @Override
1408    public Long zrem(Object key, Object... members) {
1409        Jedis jedis = getJedis();
1410        try {
1411            return jedis.zrem(keyToBytes(key), valuesToBytesArray(members));
1412        } finally {
1413            returnResource(jedis);
1414        }
1415    }
1416
1417    /**
1418     * 返回有序集 key 中,成员 member 的 score 值。
1419     * 如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。
1420     */
1421    @Override
1422    public Double zscore(Object key, Object member) {
1423        Jedis jedis = getJedis();
1424        try {
1425            return jedis.zscore(keyToBytes(key), valueToBytes(member));
1426        } finally {
1427            returnResource(jedis);
1428        }
1429    }
1430
1431    /**
1432     * 发布
1433     *
1434     * @param channel
1435     * @param message
1436     */
1437    @Override
1438    public void publish(String channel, String message) {
1439        Jedis jedis = getJedis();
1440        try {
1441            jedis.publish(channel, message);
1442        } finally {
1443            returnResource(jedis);
1444        }
1445    }
1446
1447    /**
1448     * 发布
1449     *
1450     * @param channel
1451     * @param message
1452     */
1453    @Override
1454    public void publish(byte[] channel, byte[] message) {
1455        Jedis jedis = getJedis();
1456        try {
1457            jedis.publish(channel, message);
1458        } finally {
1459            returnResource(jedis);
1460        }
1461    }
1462
1463
1464    /**
1465     * 订阅
1466     *
1467     * @param listener
1468     * @param channels
1469     */
1470    @Override
1471    public void subscribe(JedisPubSub listener, final String... channels) {
1472        /**
1473         * https://github.com/xetorthio/jedis/wiki/AdvancedUsage
1474         * Note that subscribe is a blocking operation because it will poll JbootRedis for responses on the thread that calls subscribe.
1475         * A single JedisPubSub instance can be used to subscribe to multiple channels.
1476         * You can call subscribe or psubscribe on an existing JedisPubSub instance to change your subscriptions.
1477         */
1478        new Thread("jboot-redis-subscribe-JedisPubSub") {
1479            @Override
1480            public void run() {
1481                while (true) {
1482                    Jedis jedis = getJedis();
1483                    try {
1484                        // subscribe 方法是阻塞的,不用担心会走到returnResource,除非异常
1485                        jedis.subscribe(listener, channels);
1486                        LOG.warn("Disconnect to redis channels : " + Arrays.toString(channels));
1487                        break;
1488                    } catch (JedisConnectionException e) {
1489                        LOG.error("Failed connect to redis, reconnect it.", e);
1490                        QuietlyUtil.sleepQuietly(1000);
1491                    } finally {
1492                        returnResource(jedis);
1493                    }
1494                }
1495
1496
1497            }
1498        }.start();
1499    }
1500
1501    /**
1502     * 订阅
1503     *
1504     * @param binaryListener
1505     * @param channels
1506     */
1507    @Override
1508    public void subscribe(BinaryJedisPubSub binaryListener, final byte[]... channels) {
1509        /**
1510         * https://github.com/xetorthio/jedis/wiki/AdvancedUsage
1511         * Note that subscribe is a blocking operation because it will poll JbootRedis for responses on the thread that calls subscribe.
1512         * A single JedisPubSub instance can be used to subscribe to multiple channels.
1513         * You can call subscribe or psubscribe on an existing JedisPubSub instance to change your subscriptions.
1514         */
1515        new Thread("jboot-redis-subscribe-BinaryJedisPubSub") {
1516            @Override
1517            public void run() {
1518                //订阅线程断开连接,需要进行重连
1519                while (!isClose()) {
1520                    Jedis jedis = null;
1521                    try {
1522                        jedis = jedisPool.getResource();
1523                        // subscribe 方法是阻塞的,不用担心会走到returnResource,除非异常
1524                        jedis.subscribe(binaryListener, channels);
1525                        LOG.warn("Disconnect to redis channel in subscribe binaryListener!");
1526                        break;
1527                    } catch (Throwable e) {
1528                        LOG.error("Failed connect to redis, reconnect it.", e);
1529                        QuietlyUtil.sleepQuietly(1000);
1530                    } finally {
1531                        if (jedis != null) {
1532                            returnResource(jedis);
1533                        }
1534                    }
1535                }
1536            }
1537        }.start();
1538    }
1539
1540    @Override
1541    public RedisScanResult<String> scan(String pattern, String cursor, int scanCount) {
1542        ScanParams params = new ScanParams();
1543        params.match(pattern).count(scanCount);
1544        try (Jedis jedis = getJedis()) {
1545            ScanResult<String> scanResult = jedis.scan(cursor, params);
1546            return new RedisScanResult<>(scanResult.getCursor(), scanResult.getResult());
1547        }
1548    }
1549
1550    @Override
1551    public Object eval(String script, int keyCount, String... params) {
1552        Jedis jedis = getJedis();
1553        try {
1554            return jedis.eval(script, keyCount, params);
1555        } finally {
1556            returnResource(jedis);
1557        }
1558    }
1559
1560    public Jedis getJedis() {
1561        try {
1562            return jedisPool.getResource();
1563        } catch (JedisConnectionException e) {
1564            throw new JbootIllegalConfigException("can not connect to redis host  " + config.getHost() + ":" + config.getPort() + " ," +
1565                    " cause : " + e.toString(), e);
1566        }
1567    }
1568
1569    public JedisPool getJedisPool() {
1570        return jedisPool;
1571    }
1572
1573    public void returnResource(Jedis jedis) {
1574        if (jedis != null) {
1575            jedis.close();
1576        }
1577    }
1578
1579
1580}
1581
1582
1583
1584
1585
1586