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