xiejun
2024-11-01 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a
Source/BladeX-Tool/blade-starter-redis/src/main/java/org/springblade/core/redis/cache/BladeRedis.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,824 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.redis.cache;
import lombok.Getter;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springframework.data.redis.core.*;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
 * redis å·¥å…·
 *
 * @author L.cm
 */
@Getter
@SuppressWarnings("unchecked")
public class BladeRedis {
   private final RedisTemplate<String, Object> redisTemplate;
   private final StringRedisTemplate stringRedisTemplate;
   private final ValueOperations<String, Object> valueOps;
   private final HashOperations<String, Object, Object> hashOps;
   private final ListOperations<String, Object> listOps;
   private final SetOperations<String, Object> setOps;
   private final ZSetOperations<String, Object> zSetOps;
   public BladeRedis(RedisTemplate<String, Object> redisTemplate, StringRedisTemplate stringRedisTemplate) {
      this.redisTemplate = redisTemplate;
      this.stringRedisTemplate = stringRedisTemplate;
      Assert.notNull(redisTemplate, "redisTemplate is null");
      valueOps = redisTemplate.opsForValue();
      hashOps = redisTemplate.opsForHash();
      listOps = redisTemplate.opsForList();
      setOps = redisTemplate.opsForSet();
      zSetOps = redisTemplate.opsForZSet();
   }
   /**
    * è®¾ç½®ç¼“å­˜
    *
    * @param cacheKey ç¼“å­˜key
    * @param value    ç¼“å­˜value
    */
   public void set(CacheKey cacheKey, Object value) {
      String key = cacheKey.getKey();
      Duration expire = cacheKey.getExpire();
      if (expire == null) {
         set(key, value);
      } else {
         setEx(key, value, expire);
      }
   }
   /**
    * å­˜æ”¾ key value å¯¹åˆ° redis。
    */
   public void set(String key, Object value) {
      valueOps.set(key, value);
   }
   /**
    * å­˜æ”¾ key value å¯¹åˆ° redis,并将 key çš„生存时间设为 seconds (以秒为单位)。
    * å¦‚æžœ key å·²ç»å­˜åœ¨ï¼Œ SETEX å‘½ä»¤å°†è¦†å†™æ—§å€¼ã€‚
    */
   public void setEx(String key, Object value, Duration timeout) {
      valueOps.set(key, value, timeout);
   }
   /**
    * å­˜æ”¾ key value å¯¹åˆ° redis,并将 key çš„生存时间设为 seconds (以秒为单位)。
    * å¦‚æžœ key å·²ç»å­˜åœ¨ï¼Œ SETEX å‘½ä»¤å°†è¦†å†™æ—§å€¼ã€‚
    */
   public void setEx(String key, Object value, Long seconds) {
      valueOps.set(key, value, seconds, TimeUnit.SECONDS);
   }
   /**
    * è¿”回 key æ‰€å…³è”çš„ value å€¼
    * å¦‚æžœ key ä¸å­˜åœ¨é‚£ä¹ˆè¿”回特殊值 nil ã€‚
    */
   @Nullable
   public <T> T get(String key) {
      return (T) valueOps.get(key);
   }
   /**
    * èŽ·å–cache ä¸º null æ—¶ä½¿ç”¨åŠ è½½å™¨ï¼Œç„¶åŽè®¾ç½®ç¼“å­˜
    *
    * @param key    cacheKey
    * @param loader cache loader
    * @param <T>    æ³›åž‹
    * @return ç»“æžœ
    */
   @Nullable
   public <T> T get(String key, Supplier<T> loader) {
      T value = this.get(key);
      if (value != null) {
         return value;
      }
      value = loader.get();
      if (value == null) {
         return null;
      }
      this.set(key, value);
      return value;
   }
   /**
    * è¿”回 key æ‰€å…³è”çš„ value å€¼
    * å¦‚æžœ key ä¸å­˜åœ¨é‚£ä¹ˆè¿”回特殊值 nil ã€‚
    */
   @Nullable
   public <T> T get(CacheKey cacheKey) {
      return (T) valueOps.get(cacheKey.getKey());
   }
   /**
    * èŽ·å–cache ä¸º null æ—¶ä½¿ç”¨åŠ è½½å™¨ï¼Œç„¶åŽè®¾ç½®ç¼“å­˜
    *
    * @param cacheKey cacheKey
    * @param loader   cache loader
    * @param <T>      æ³›åž‹
    * @return ç»“æžœ
    */
   @Nullable
   public <T> T get(CacheKey cacheKey, Supplier<T> loader) {
      String key = cacheKey.getKey();
      T value = this.get(key);
      if (value != null) {
         return value;
      }
      value = loader.get();
      if (value == null) {
         return null;
      }
      this.set(cacheKey, value);
      return value;
   }
   /**
    * åˆ é™¤ç»™å®šçš„一个 key
    * ä¸å­˜åœ¨çš„ key ä¼šè¢«å¿½ç•¥ã€‚
    */
   public Boolean del(String key) {
      return redisTemplate.delete(key);
   }
   /**
    * åˆ é™¤ç»™å®šçš„一个 key
    * ä¸å­˜åœ¨çš„ key ä¼šè¢«å¿½ç•¥ã€‚
    */
   public Boolean del(CacheKey key) {
      return redisTemplate.delete(key.getKey());
   }
   /**
    * åˆ é™¤ç»™å®šçš„多个 key
    * ä¸å­˜åœ¨çš„ key ä¼šè¢«å¿½ç•¥ã€‚
    */
   public Long del(String... keys) {
      return del(Arrays.asList(keys));
   }
   /**
    * åˆ é™¤ç»™å®šçš„多个 key
    * ä¸å­˜åœ¨çš„ key ä¼šè¢«å¿½ç•¥ã€‚
    */
   public Long del(Collection<String> keys) {
      return redisTemplate.delete(keys);
   }
   /**
    * æŸ¥æ‰¾æ‰€æœ‰ç¬¦åˆç»™å®šæ¨¡å¼ pattern çš„ key ã€‚
    * KEYS * åŒ¹é…æ•°æ®åº“中所有 key ã€‚
    * KEYS h?llo åŒ¹é… hello ï¼Œ hallo å’Œ hxllo ç­‰ã€‚
    * KEYS h*llo åŒ¹é… hllo å’Œ heeeeello ç­‰ã€‚
    * KEYS h[ae]llo åŒ¹é… hello å’Œ hallo ï¼Œä½†ä¸åŒ¹é… hillo ã€‚
    * ç‰¹æ®Šç¬¦å·ç”¨ \ éš”å¼€
    */
   public Set<String> keys(String pattern) {
      return redisTemplate.keys(pattern);
   }
   /**
    * åŒæ—¶è®¾ç½®ä¸€ä¸ªæˆ–多个 key-value å¯¹ã€‚
    * å¦‚果某个给定 key å·²ç»å­˜åœ¨ï¼Œé‚£ä¹ˆ MSET ä¼šç”¨æ–°å€¼è¦†ç›–原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX å‘½ä»¤ï¼šå®ƒåªä¼šåœ¨æ‰€æœ‰ç»™å®š key éƒ½ä¸å­˜åœ¨çš„æƒ…况下进行设置操作。
    * MSET æ˜¯ä¸€ä¸ªåŽŸå­æ€§(atomic)操作,所有给定 key éƒ½ä¼šåœ¨åŒä¸€æ—¶é—´å†…被设置,某些给定 key è¢«æ›´æ–°è€Œå¦ä¸€äº›ç»™å®š key æ²¡æœ‰æ”¹å˜çš„æƒ…况,不可能发生。
    * <pre>
    * ä¾‹å­ï¼š
    * Cache cache = RedisKit.use();         // ä½¿ç”¨ Redis çš„ cache
    * cache.mset("k1", "v1", "k2", "v2");      // æ”¾å…¥å¤šä¸ª key value é”®å€¼å¯¹
    * List list = cache.mget("k1", "k2");      // åˆ©ç”¨å¤šä¸ªé”®å€¼å¾—到上面代码放入的值
    * </pre>
    */
   public void mSet(Object... keysValues) {
      valueOps.multiSet(CollectionUtil.toMap(keysValues));
   }
   /**
    * è¿”回所有(一个或多个)给定 key çš„值。
    * å¦‚果给定的 key é‡Œé¢ï¼Œæœ‰æŸä¸ª key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆè¿™ä¸ª key è¿”回特殊值 nil ã€‚因此,该命令永不失败。
    */
   public List<Object> mGet(String... keys) {
      return mGet(Arrays.asList(keys));
   }
   /**
    * è¿”回所有(一个或多个)给定 key çš„值。
    * å¦‚果给定的 key é‡Œé¢ï¼Œæœ‰æŸä¸ª key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆè¿™ä¸ª key è¿”回特殊值 nil ã€‚因此,该命令永不失败。
    */
   public List<Object> mGet(Collection<String> keys) {
      return valueOps.multiGet(keys);
   }
   /**
    * å°† key ä¸­å‚¨å­˜çš„æ•°å­—值减一。
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ key çš„值会先被初始化为 0 ï¼Œç„¶åŽå†æ‰§è¡Œ DECR æ“ä½œã€‚
    * å¦‚果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
    * æœ¬æ“ä½œçš„值限制在 64 ä½(bit)有符号数字表示之内。
    * å…³äºŽé€’增(increment) / é€’减(decrement)操作的更多信息,请参见 INCR å‘½ä»¤ã€‚
    */
   public Long decr(String key) {
      return stringRedisTemplate.opsForValue().decrement(key);
   }
   /**
    * å°† key æ‰€å‚¨å­˜çš„值减去减量 decrement ã€‚
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ key çš„值会先被初始化为 0 ï¼Œç„¶åŽå†æ‰§è¡Œ DECRBY æ“ä½œã€‚
    * å¦‚果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
    * æœ¬æ“ä½œçš„值限制在 64 ä½(bit)有符号数字表示之内。
    * å…³äºŽæ›´å¤šé€’增(increment) / é€’减(decrement)操作的更多信息,请参见 INCR å‘½ä»¤ã€‚
    */
   public Long decrBy(String key, long longValue) {
      return stringRedisTemplate.opsForValue().decrement(key, longValue);
   }
   /**
    * å°† key ä¸­å‚¨å­˜çš„æ•°å­—值增一。
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ key çš„值会先被初始化为 0 ï¼Œç„¶åŽå†æ‰§è¡Œ INCR æ“ä½œã€‚
    * å¦‚果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
    * æœ¬æ“ä½œçš„值限制在 64 ä½(bit)有符号数字表示之内。
    */
   public Long incr(String key) {
      return stringRedisTemplate.opsForValue().increment(key);
   }
   /**
    * å°† key æ‰€å‚¨å­˜çš„值加上增量 increment ã€‚
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ key çš„值会先被初始化为 0 ï¼Œç„¶åŽå†æ‰§è¡Œ INCRBY å‘½ä»¤ã€‚
    * å¦‚果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
    * æœ¬æ“ä½œçš„值限制在 64 ä½(bit)有符号数字表示之内。
    * å…³äºŽé€’增(increment) / é€’减(decrement)操作的更多信息,参见 INCR å‘½ä»¤ã€‚
    */
   public Long incrBy(String key, long longValue) {
      return stringRedisTemplate.opsForValue().increment(key, longValue);
   }
   /**
    * èŽ·å–è®°æ•°å™¨çš„å€¼
    */
   public Long getCounter(String key) {
      return Long.valueOf(String.valueOf(valueOps.get(key)));
   }
   /**
    * æ£€æŸ¥ç»™å®š key æ˜¯å¦å­˜åœ¨ã€‚
    */
   public Boolean exists(String key) {
      return redisTemplate.hasKey(key);
   }
   /**
    * ä»Žå½“前数据库中随机返回(不删除)一个 key ã€‚
    */
   public String randomKey() {
      return redisTemplate.randomKey();
   }
   /**
    * å°† key æ”¹åä¸º newkey ã€‚
    * å½“ key å’Œ newkey ç›¸åŒï¼Œæˆ–者 key ä¸å­˜åœ¨æ—¶ï¼Œè¿”回一个错误。
    * å½“ newkey å·²ç»å­˜åœ¨æ—¶ï¼Œ RENAME å‘½ä»¤å°†è¦†ç›–旧值。
    */
   public void rename(String oldkey, String newkey) {
      redisTemplate.rename(oldkey, newkey);
   }
   /**
    * å°†å½“前数据库的 key ç§»åŠ¨åˆ°ç»™å®šçš„æ•°æ®åº“ db å½“中。
    * å¦‚果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ï¼Œæˆ–者 key ä¸å­˜åœ¨äºŽå½“前数据库,那么 MOVE æ²¡æœ‰ä»»ä½•效果。
    * å› æ­¤ï¼Œä¹Ÿå¯ä»¥åˆ©ç”¨è¿™ä¸€ç‰¹æ€§ï¼Œå°† MOVE å½“作锁(locking)原语(primitive)。
    */
   public Boolean move(String key, int dbIndex) {
      return redisTemplate.move(key, dbIndex);
   }
   /**
    * ä¸ºç»™å®š key è®¾ç½®ç”Ÿå­˜æ—¶é—´ï¼Œå½“ key è¿‡æœŸæ—¶(生存时间为 0 ),它会被自动删除。
    * åœ¨ Redis ä¸­ï¼Œå¸¦æœ‰ç”Ÿå­˜æ—¶é—´çš„ key è¢«ç§°ä¸ºã€Žæ˜“失的』(volatile)。
    */
   public Boolean expire(String key, long seconds) {
      return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
   }
   /**
    * ä¸ºç»™å®š key è®¾ç½®ç”Ÿå­˜æ—¶é—´ï¼Œå½“ key è¿‡æœŸæ—¶(生存时间为 0 ),它会被自动删除。
    * åœ¨ Redis ä¸­ï¼Œå¸¦æœ‰ç”Ÿå­˜æ—¶é—´çš„ key è¢«ç§°ä¸ºã€Žæ˜“失的』(volatile)。
    */
   public Boolean expire(String key, Duration timeout) {
      return expire(key, timeout.getSeconds());
   }
   /**
    * EXPIREAT çš„作用和 EXPIRE ç±»ä¼¼ï¼Œéƒ½ç”¨äºŽä¸º key è®¾ç½®ç”Ÿå­˜æ—¶é—´ã€‚不同在于 EXPIREAT å‘½ä»¤æŽ¥å—的时间参数是 UNIX æ—¶é—´æˆ³(unix timestamp)。
    */
   public Boolean expireAt(String key, Date date) {
      return redisTemplate.expireAt(key, date);
   }
   /**
    * EXPIREAT çš„作用和 EXPIRE ç±»ä¼¼ï¼Œéƒ½ç”¨äºŽä¸º key è®¾ç½®ç”Ÿå­˜æ—¶é—´ã€‚不同在于 EXPIREAT å‘½ä»¤æŽ¥å—的时间参数是 UNIX æ—¶é—´æˆ³(unix timestamp)。
    */
   public Boolean expireAt(String key, long unixTime) {
      return expireAt(key, new Date(unixTime));
   }
   /**
    * è¿™ä¸ªå‘½ä»¤å’Œ EXPIRE å‘½ä»¤çš„作用类似,但是它以毫秒为单位设置 key çš„生存时间,而不像 EXPIRE å‘½ä»¤é‚£æ ·ï¼Œä»¥ç§’为单位。
    */
   public Boolean pexpire(String key, long milliseconds) {
      return redisTemplate.expire(key, milliseconds, TimeUnit.MILLISECONDS);
   }
   /**
    * å°†ç»™å®š key çš„值设为 value ï¼Œå¹¶è¿”回 key çš„æ—§å€¼(old value)。
    * å½“ key å­˜åœ¨ä½†ä¸æ˜¯å­—符串类型时,返回一个错误。
    */
   public <T> T getSet(String key, Object value) {
      return (T) valueOps.getAndSet(key, value);
   }
   /**
    * ç§»é™¤ç»™å®š key çš„生存时间,将这个 key ä»Žã€Žæ˜“失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
    */
   public Boolean persist(String key) {
      return redisTemplate.persist(key);
   }
   /**
    * è¿”回 key æ‰€å‚¨å­˜çš„值的类型。
    */
   public String type(String key) {
      return redisTemplate.type(key).code();
   }
   /**
    * ä»¥ç§’为单位,返回给定 key çš„剩余生存时间(TTL, time to live)。
    */
   public Long ttl(String key) {
      return redisTemplate.getExpire(key);
   }
   /**
    * è¿™ä¸ªå‘½ä»¤ç±»ä¼¼äºŽ TTL å‘½ä»¤ï¼Œä½†å®ƒä»¥æ¯«ç§’为单位返回 key çš„剩余生存时间,而不是像 TTL å‘½ä»¤é‚£æ ·ï¼Œä»¥ç§’为单位。
    */
   public Long pttl(String key) {
      return redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
   }
   /**
    * å°†å“ˆå¸Œè¡¨ key ä¸­çš„域 field çš„值设为 value ã€‚
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œä¸€ä¸ªæ–°çš„哈希表被创建并进行 HSET æ“ä½œã€‚
    * å¦‚果域 field å·²ç»å­˜åœ¨äºŽå“ˆå¸Œè¡¨ä¸­ï¼Œæ—§å€¼å°†è¢«è¦†ç›–。
    */
   public void hSet(String key, Object field, Object value) {
      hashOps.put(key, field, value);
   }
   /**
    * åŒæ—¶å°†å¤šä¸ª field-value (域-值)对设置到哈希表 key ä¸­ã€‚
    * æ­¤å‘½ä»¤ä¼šè¦†ç›–哈希表中已存在的域。
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œä¸€ä¸ªç©ºå“ˆå¸Œè¡¨è¢«åˆ›å»ºå¹¶æ‰§è¡Œ HMSET æ“ä½œã€‚
    */
   public void hMset(String key, Map<Object, Object> hash) {
      hashOps.putAll(key, hash);
   }
   /**
    * è¿”回哈希表 key ä¸­ç»™å®šåŸŸ field çš„值。
    */
   public <T> T hGet(String key, Object field) {
      return (T) hashOps.get(key, field);
   }
   /**
    * è¿”回哈希表 key ä¸­ï¼Œä¸€ä¸ªæˆ–多个给定域的值。
    * å¦‚果给定的域不存在于哈希表,那么返回一个 nil å€¼ã€‚
    * å› ä¸ºä¸å­˜åœ¨çš„ key è¢«å½“作一个空哈希表来处理,所以对一个不存在的 key è¿›è¡Œ HMGET æ“ä½œå°†è¿”回一个只带有 nil å€¼çš„表。
    */
   public List hmGet(String key, Object... fields) {
      return hmGet(key, Arrays.asList(fields));
   }
   /**
    * è¿”回哈希表 key ä¸­ï¼Œä¸€ä¸ªæˆ–多个给定域的值。
    * å¦‚果给定的域不存在于哈希表,那么返回一个 nil å€¼ã€‚
    * å› ä¸ºä¸å­˜åœ¨çš„ key è¢«å½“作一个空哈希表来处理,所以对一个不存在的 key è¿›è¡Œ HMGET æ“ä½œå°†è¿”回一个只带有 nil å€¼çš„表。
    */
   public List hmGet(String key, Collection<Object> hashKeys) {
      return hashOps.multiGet(key, hashKeys);
   }
   /**
    * åˆ é™¤å“ˆå¸Œè¡¨ key ä¸­çš„一个或多个指定域,不存在的域将被忽略。
    */
   public Long hDel(String key, Object... fields) {
      return hashOps.delete(key, fields);
   }
   /**
    * æŸ¥çœ‹å“ˆå¸Œè¡¨ key ä¸­ï¼Œç»™å®šåŸŸ field æ˜¯å¦å­˜åœ¨ã€‚
    */
   public Boolean hExists(String key, Object field) {
      return hashOps.hasKey(key, field);
   }
   /**
    * è¿”回哈希表 key ä¸­ï¼Œæ‰€æœ‰çš„域和值。
    * åœ¨è¿”回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
    */
   public Map hGetAll(String key) {
      return hashOps.entries(key);
   }
   /**
    * è¿”回哈希表 key ä¸­æ‰€æœ‰åŸŸçš„值。
    */
   public List hVals(String key) {
      return hashOps.values(key);
   }
   /**
    * è¿”回哈希表 key ä¸­çš„æ‰€æœ‰åŸŸã€‚
    * åº•层实现此方法取名为 hfields æ›´ä¸ºåˆé€‚,在此仅为与底层保持一致
    */
   public Set<Object> hKeys(String key) {
      return hashOps.keys(key);
   }
   /**
    * è¿”回哈希表 key ä¸­åŸŸçš„æ•°é‡ã€‚
    */
   public Long hLen(String key) {
      return hashOps.size(key);
   }
   /**
    * ä¸ºå“ˆå¸Œè¡¨ key ä¸­çš„域 field çš„值加上增量 increment ã€‚
    * å¢žé‡ä¹Ÿå¯ä»¥ä¸ºè´Ÿæ•°ï¼Œç›¸å½“于对给定域进行减法操作。
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œä¸€ä¸ªæ–°çš„哈希表被创建并执行 HINCRBY å‘½ä»¤ã€‚
    * å¦‚果域 field ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆåœ¨æ‰§è¡Œå‘½ä»¤å‰ï¼ŒåŸŸçš„值被初始化为 0 ã€‚
    * å¯¹ä¸€ä¸ªå‚¨å­˜å­—符串值的域 field æ‰§è¡Œ HINCRBY å‘½ä»¤å°†é€ æˆä¸€ä¸ªé”™è¯¯ã€‚
    * æœ¬æ“ä½œçš„值被限制在 64 ä½(bit)有符号数字表示之内。
    */
   public Long hIncrBy(String key, Object field, long value) {
      return hashOps.increment(key, field, value);
   }
   /**
    * ä¸ºå“ˆå¸Œè¡¨ key ä¸­çš„域 field åŠ ä¸Šæµ®ç‚¹æ•°å¢žé‡ increment ã€‚
    * å¦‚果哈希表中没有域 field ï¼Œé‚£ä¹ˆ HINCRBYFLOAT ä¼šå…ˆå°†åŸŸ field çš„值设为 0 ï¼Œç„¶åŽå†æ‰§è¡ŒåŠ æ³•æ“ä½œã€‚
    * å¦‚果键 key ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ HINCRBYFLOAT ä¼šå…ˆåˆ›å»ºä¸€ä¸ªå“ˆå¸Œè¡¨ï¼Œå†åˆ›å»ºåŸŸ field ï¼Œæœ€åŽå†æ‰§è¡ŒåŠ æ³•æ“ä½œã€‚
    * å½“以下任意一个条件发生时,返回一个错误:
    * 1:域 field çš„值不是字符串类型(因为 redis ä¸­çš„æ•°å­—和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
    * 2:域 field å½“前的值或给定的增量 increment ä¸èƒ½è§£é‡Š(parse)为双精度浮点数(double precision floating point number)
    * HINCRBYFLOAT å‘½ä»¤çš„详细功能和 INCRBYFLOAT å‘½ä»¤ç±»ä¼¼ï¼Œè¯·æŸ¥çœ‹ INCRBYFLOAT å‘½ä»¤èŽ·å–æ›´å¤šç›¸å…³ä¿¡æ¯ã€‚
    */
   public Double hIncrByFloat(String key, Object field, double value) {
      return hashOps.increment(key, field, value);
   }
   /**
    * è¿”回列表 key ä¸­ï¼Œä¸‹æ ‡ä¸º index çš„元素。
    * ä¸‹æ ‡(index)参数 start å’Œ stop éƒ½ä»¥ 0 ä¸ºåº•,也就是说,以 0 è¡¨ç¤ºåˆ—表的第一个元素,
    * ä»¥ 1 è¡¨ç¤ºåˆ—表的第二个元素,以此类推。
    * ä½ ä¹Ÿå¯ä»¥ä½¿ç”¨è´Ÿæ•°ä¸‹æ ‡ï¼Œä»¥ -1 è¡¨ç¤ºåˆ—表的最后一个元素, -2 è¡¨ç¤ºåˆ—表的倒数第二个元素,以此类推。
    * å¦‚æžœ key ä¸æ˜¯åˆ—表类型,返回一个错误。
    */
   public <T> T lIndex(String key, long index) {
      return (T) listOps.index(key, index);
   }
   /**
    * è¿”回列表 key çš„长度。
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œåˆ™ key è¢«è§£é‡Šä¸ºä¸€ä¸ªç©ºåˆ—表,返回 0 .
    * å¦‚æžœ key ä¸æ˜¯åˆ—表类型,返回一个错误。
    */
   public Long lLen(String key) {
      return listOps.size(key);
   }
   /**
    * ç§»é™¤å¹¶è¿”回列表 key çš„头元素。
    */
   public <T> T lPop(String key) {
      return (T) listOps.leftPop(key);
   }
   /**
    * å°†ä¸€ä¸ªæˆ–多个值 value æ’入到列表 key çš„表头
    * å¦‚果有多个 value å€¼ï¼Œé‚£ä¹ˆå„个 value å€¼æŒ‰ä»Žå·¦åˆ°å³çš„顺序依次插入到表头: æ¯”如说,
    * å¯¹ç©ºåˆ—表 mylist æ‰§è¡Œå‘½ä»¤ LPUSH mylist a b c ï¼Œåˆ—表的值将是 c b a ï¼Œ
    * è¿™ç­‰åŒäºŽåŽŸå­æ€§åœ°æ‰§è¡Œ LPUSH mylist a ã€ LPUSH mylist b å’Œ LPUSH mylist c ä¸‰ä¸ªå‘½ä»¤ã€‚
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œä¸€ä¸ªç©ºåˆ—表会被创建并执行 LPUSH æ“ä½œã€‚
    * å½“ key å­˜åœ¨ä½†ä¸æ˜¯åˆ—表类型时,返回一个错误。
    */
   public Long lPush(String key, Object... values) {
      return listOps.leftPush(key, values);
   }
   /**
    * å°†åˆ—表 key ä¸‹æ ‡ä¸º index çš„元素的值设置为 value ã€‚
    * å½“ index å‚数超出范围,或对一个空列表( key ä¸å­˜åœ¨)进行 LSET æ—¶ï¼Œè¿”回一个错误。
    * å…³äºŽåˆ—表下标的更多信息,请参考 LINDEX å‘½ä»¤ã€‚
    */
   public void lSet(String key, long index, Object value) {
      listOps.set(key, index, value);
   }
   /**
    * æ ¹æ®å‚æ•° count çš„值,移除列表中与参数 value ç›¸ç­‰çš„元素。
    * count çš„值可以是以下几种:
    * count > 0 : ä»Žè¡¨å¤´å¼€å§‹å‘表尾搜索,移除与 value ç›¸ç­‰çš„元素,数量为 count ã€‚
    * count < 0 : ä»Žè¡¨å°¾å¼€å§‹å‘表头搜索,移除与 value ç›¸ç­‰çš„元素,数量为 count çš„绝对值。
    * count = 0 : ç§»é™¤è¡¨ä¸­æ‰€æœ‰ä¸Ž value ç›¸ç­‰çš„值。
    */
   public Long lRem(String key, long count, Object value) {
      return listOps.remove(key, count, value);
   }
   /**
    * è¿”回列表 key ä¸­æŒ‡å®šåŒºé—´å†…的元素,区间以偏移量 start å’Œ stop æŒ‡å®šã€‚
    * ä¸‹æ ‡(index)参数 start å’Œ stop éƒ½ä»¥ 0 ä¸ºåº•,也就是说,以 0 è¡¨ç¤ºåˆ—表的第一个元素,以 1 è¡¨ç¤ºåˆ—表的第二个元素,以此类推。
    * ä½ ä¹Ÿå¯ä»¥ä½¿ç”¨è´Ÿæ•°ä¸‹æ ‡ï¼Œä»¥ -1 è¡¨ç¤ºåˆ—表的最后一个元素, -2 è¡¨ç¤ºåˆ—表的倒数第二个元素,以此类推。
    * <pre>
    * ä¾‹å­ï¼š
    * èŽ·å– list ä¸­æ‰€æœ‰æ•°æ®ï¼šcache.lrange(listKey, 0, -1);
    * èŽ·å– list ä¸­ä¸‹æ ‡ 1 åˆ° 3 çš„æ•°æ®ï¼š cache.lrange(listKey, 1, 3);
    * </pre>
    */
   public List lRange(String key, long start, long end) {
      return listOps.range(key, start, end);
   }
   /**
    * å¯¹ä¸€ä¸ªåˆ—表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
    * ä¸¾ä¸ªä¾‹å­ï¼Œæ‰§è¡Œå‘½ä»¤ LTRIM list 0 2 ï¼Œè¡¨ç¤ºåªä¿ç•™åˆ—表 list çš„前三个元素,其余元素全部删除。
    * ä¸‹æ ‡(index)参数 start å’Œ stop éƒ½ä»¥ 0 ä¸ºåº•,也就是说,以 0 è¡¨ç¤ºåˆ—表的第一个元素,以 1 è¡¨ç¤ºåˆ—表的第二个元素,以此类推。
    * ä½ ä¹Ÿå¯ä»¥ä½¿ç”¨è´Ÿæ•°ä¸‹æ ‡ï¼Œä»¥ -1 è¡¨ç¤ºåˆ—表的最后一个元素, -2 è¡¨ç¤ºåˆ—表的倒数第二个元素,以此类推。
    * å½“ key ä¸æ˜¯åˆ—表类型时,返回一个错误。
    */
   public void lTrim(String key, long start, long end) {
      listOps.trim(key, start, end);
   }
   /**
    * ç§»é™¤å¹¶è¿”回列表 key çš„尾元素。
    */
   public <T> T rPop(String key) {
      return (T) listOps.rightPop(key);
   }
   /**
    * å°†ä¸€ä¸ªæˆ–多个值 value æ’入到列表 key çš„表尾(最右边)。
    * å¦‚果有多个 value å€¼ï¼Œé‚£ä¹ˆå„个 value å€¼æŒ‰ä»Žå·¦åˆ°å³çš„顺序依次插入到表尾:比如
    * å¯¹ä¸€ä¸ªç©ºåˆ—表 mylist æ‰§è¡Œ RPUSH mylist a b c ï¼Œå¾—出的结果列表为 a b c ï¼Œ
    * ç­‰åŒäºŽæ‰§è¡Œå‘½ä»¤ RPUSH mylist a ã€ RPUSH mylist b ã€ RPUSH mylist c ã€‚
    * å¦‚æžœ key ä¸å­˜åœ¨ï¼Œä¸€ä¸ªç©ºåˆ—表会被创建并执行 RPUSH æ“ä½œã€‚
    * å½“ key å­˜åœ¨ä½†ä¸æ˜¯åˆ—表类型时,返回一个错误。
    */
   public Long rPush(String key, Object... values) {
      return listOps.rightPush(key, values);
   }
   /**
    * å‘½ä»¤ RPOPLPUSH åœ¨ä¸€ä¸ªåŽŸå­æ—¶é—´å†…ï¼Œæ‰§è¡Œä»¥ä¸‹ä¸¤ä¸ªåŠ¨ä½œï¼š
    * å°†åˆ—表 source ä¸­çš„æœ€åŽä¸€ä¸ªå…ƒç´ (尾元素)弹出,并返回给客户端。
    * å°† source å¼¹å‡ºçš„元素插入到列表 destination ï¼Œä½œä¸º destination åˆ—表的的头元素。
    */
   public <T> T rPopLPush(String srcKey, String dstKey) {
      return (T) listOps.rightPopAndLeftPush(srcKey, dstKey);
   }
   /**
    * å°†ä¸€ä¸ªæˆ–多个 member å…ƒç´ åŠ å…¥åˆ°é›†åˆ key å½“中,已经存在于集合的 member å…ƒç´ å°†è¢«å¿½ç•¥ã€‚
    * å‡å¦‚ key ä¸å­˜åœ¨ï¼Œåˆ™åˆ›å»ºä¸€ä¸ªåªåŒ…含 member å…ƒç´ ä½œæˆå‘˜çš„集合。
    * å½“ key ä¸æ˜¯é›†åˆç±»åž‹æ—¶ï¼Œè¿”回一个错误。
    */
   public Long sAdd(String key, Object... members) {
      return setOps.add(key, members);
   }
   /**
    * ç§»é™¤å¹¶è¿”回集合中的一个随机元素。
    * å¦‚果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER å‘½ä»¤ã€‚
    */
   public <T> T sPop(String key) {
      return (T) setOps.pop(key);
   }
   /**
    * è¿”回集合 key ä¸­çš„æ‰€æœ‰æˆå‘˜ã€‚
    * ä¸å­˜åœ¨çš„ key è¢«è§†ä¸ºç©ºé›†åˆã€‚
    */
   public Set sMembers(String key) {
      return setOps.members(key);
   }
   /**
    * åˆ¤æ–­ member å…ƒç´ æ˜¯å¦é›†åˆ key çš„æˆå‘˜ã€‚
    */
   public boolean sIsMember(String key, Object member) {
      return setOps.isMember(key, member);
   }
   /**
    * è¿”回多个集合的交集,多个集合由 keys æŒ‡å®š
    */
   public Set sInter(String key, String otherKey) {
      return setOps.intersect(key, otherKey);
   }
   /**
    * è¿”回多个集合的交集,多个集合由 keys æŒ‡å®š
    */
   public Set sInter(String key, Collection<String> otherKeys) {
      return setOps.intersect(key, otherKeys);
   }
   /**
    * è¿”回集合中的一个随机元素。
    */
   public <T> T sRandMember(String key) {
      return (T) setOps.randomMember(key);
   }
   /**
    * è¿”回集合中的 count ä¸ªéšæœºå…ƒç´ ã€‚
    * ä»Ž Redis 2.6 ç‰ˆæœ¬å¼€å§‹ï¼Œ SRANDMEMBER å‘½ä»¤æŽ¥å—可选的 count å‚数:
    * å¦‚æžœ count ä¸ºæ­£æ•°ï¼Œä¸”小于集合基数,那么命令返回一个包含 count ä¸ªå…ƒç´ çš„æ•°ç»„,数组中的元素各不相同。
    * å¦‚æžœ count å¤§äºŽç­‰äºŽé›†åˆåŸºæ•°ï¼Œé‚£ä¹ˆè¿”回整个集合。
    * å¦‚æžœ count ä¸ºè´Ÿæ•°ï¼Œé‚£ä¹ˆå‘½ä»¤è¿”回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count çš„绝对值。
    * è¯¥æ“ä½œå’Œ SPOP ç›¸ä¼¼ï¼Œä½† SPOP å°†éšæœºå…ƒç´ ä»Žé›†åˆä¸­ç§»é™¤å¹¶è¿”回,而 SRANDMEMBER åˆ™ä»…仅返回随机元素,而不对集合进行任何改动。
    */
   public List sRandMember(String key, int count) {
      return setOps.randomMembers(key, count);
   }
   /**
    * ç§»é™¤é›†åˆ key ä¸­çš„一个或多个 member å…ƒç´ ï¼Œä¸å­˜åœ¨çš„ member å…ƒç´ ä¼šè¢«å¿½ç•¥ã€‚
    */
   public Long sRem(String key, Object... members) {
      return setOps.remove(key, members);
   }
   /**
    * è¿”回多个集合的并集,多个集合由 keys æŒ‡å®š
    * ä¸å­˜åœ¨çš„ key è¢«è§†ä¸ºç©ºé›†ã€‚
    */
   public Set sUnion(String key, String otherKey) {
      return setOps.union(key, otherKey);
   }
   /**
    * è¿”回多个集合的并集,多个集合由 keys æŒ‡å®š
    * ä¸å­˜åœ¨çš„ key è¢«è§†ä¸ºç©ºé›†ã€‚
    */
   public Set sUnion(String key, Collection<String> otherKeys) {
      return setOps.union(key, otherKeys);
   }
   /**
    * è¿”回一个集合的全部成员,该集合是所有给定集合之间的差集。
    * ä¸å­˜åœ¨çš„ key è¢«è§†ä¸ºç©ºé›†ã€‚
    */
   public Set sDiff(String key, String otherKey) {
      return setOps.difference(key, otherKey);
   }
   /**
    * è¿”回一个集合的全部成员,该集合是所有给定集合之间的差集。
    * ä¸å­˜åœ¨çš„ key è¢«è§†ä¸ºç©ºé›†ã€‚
    */
   public Set sDiff(String key, Collection<String> otherKeys) {
      return setOps.difference(key, otherKeys);
   }
   /**
    * å°†ä¸€ä¸ªæˆ–多个 member å…ƒç´ åŠå…¶ score å€¼åŠ å…¥åˆ°æœ‰åºé›† key å½“中。
    * å¦‚果某个 member å·²ç»æ˜¯æœ‰åºé›†çš„æˆå‘˜ï¼Œé‚£ä¹ˆæ›´æ–°è¿™ä¸ª member çš„ score å€¼ï¼Œ
    * å¹¶é€šè¿‡é‡æ–°æ’入这个 member å…ƒç´ ï¼Œæ¥ä¿è¯è¯¥ member åœ¨æ­£ç¡®çš„位置上。
    */
   public Boolean zAdd(String key, Object member, double score) {
      return zSetOps.add(key, member, score);
   }
   /**
    * å°†ä¸€ä¸ªæˆ–多个 member å…ƒç´ åŠå…¶ score å€¼åŠ å…¥åˆ°æœ‰åºé›† key å½“中。
    * å¦‚果某个 member å·²ç»æ˜¯æœ‰åºé›†çš„æˆå‘˜ï¼Œé‚£ä¹ˆæ›´æ–°è¿™ä¸ª member çš„ score å€¼ï¼Œ
    * å¹¶é€šè¿‡é‡æ–°æ’入这个 member å…ƒç´ ï¼Œæ¥ä¿è¯è¯¥ member åœ¨æ­£ç¡®çš„位置上。
    */
   public Long zAdd(String key, Map<Object, Double> scoreMembers) {
      Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
      scoreMembers.forEach((k, v) -> {
         tuples.add(new DefaultTypedTuple<>(k, v));
      });
      return zSetOps.add(key, tuples);
   }
   /**
    * è¿”回有序集 key çš„基数。
    */
   public Long zCard(String key) {
      return zSetOps.zCard(key);
   }
   /**
    * è¿”回有序集 key ä¸­ï¼Œ score å€¼åœ¨ min å’Œ max ä¹‹é—´(默认包括 score å€¼ç­‰äºŽ min æˆ– max )的成员的数量。
    * å…³äºŽå‚æ•° min å’Œ max çš„详细使用方法,请参考 ZRANGEBYSCORE å‘½ä»¤ã€‚
    */
   public Long zCount(String key, double min, double max) {
      return zSetOps.count(key, min, max);
   }
   /**
    * ä¸ºæœ‰åºé›† key çš„æˆå‘˜ member çš„ score å€¼åŠ ä¸Šå¢žé‡ increment ã€‚
    */
   public Double zIncrBy(String key, Object member, double score) {
      return zSetOps.incrementScore(key, member, score);
   }
   /**
    * è¿”回有序集 key ä¸­ï¼ŒæŒ‡å®šåŒºé—´å†…的成员。
    * å…¶ä¸­æˆå‘˜çš„位置按 score å€¼é€’增(从小到大)来排序。
    * å…·æœ‰ç›¸åŒ score å€¼çš„æˆå‘˜æŒ‰å­—典序(lexicographical order )来排列。
    * å¦‚果你需要成员按 score å€¼é€’减(从大到小)来排列,请使用 ZREVRANGE å‘½ä»¤ã€‚
    */
   public Set zRange(String key, long start, long end) {
      return zSetOps.range(key, start, end);
   }
   /**
    * è¿”回有序集 key ä¸­ï¼ŒæŒ‡å®šåŒºé—´å†…的成员。
    * å…¶ä¸­æˆå‘˜çš„位置按 score å€¼é€’减(从大到小)来排列。
    * å…·æœ‰ç›¸åŒ score å€¼çš„æˆå‘˜æŒ‰å­—典序的逆序(reverse lexicographical order)排列。
    * é™¤äº†æˆå‘˜æŒ‰ score å€¼é€’减的次序排列这一点外, ZREVRANGE å‘½ä»¤çš„其他方面和 ZRANGE å‘½ä»¤ä¸€æ ·ã€‚
    */
   public Set zRevrange(String key, long start, long end) {
      return zSetOps.reverseRange(key, start, end);
   }
   /**
    * è¿”回有序集 key ä¸­ï¼Œæ‰€æœ‰ score å€¼ä»‹äºŽ min å’Œ max ä¹‹é—´(包括等于 min æˆ– max )的成员。
    * æœ‰åºé›†æˆå‘˜æŒ‰ score å€¼é€’增(从小到大)次序排列。
    */
   public Set zRangeByScore(String key, double min, double max) {
      return zSetOps.rangeByScore(key, min, max);
   }
   /**
    * è¿”回有序集 key ä¸­æˆå‘˜ member çš„æŽ’名。其中有序集成员按 score å€¼é€’增(从小到大)顺序排列。
    * æŽ’名以 0 ä¸ºåº•,也就是说, score å€¼æœ€å°çš„æˆå‘˜æŽ’名为 0 ã€‚
    * ä½¿ç”¨ ZREVRANK å‘½ä»¤å¯ä»¥èŽ·å¾—æˆå‘˜æŒ‰ score å€¼é€’减(从大到小)排列的排名。
    */
   public Long zRank(String key, Object member) {
      return zSetOps.rank(key, member);
   }
   /**
    * è¿”回有序集 key ä¸­æˆå‘˜ member çš„æŽ’名。其中有序集成员按 score å€¼é€’减(从大到小)排序。
    * æŽ’名以 0 ä¸ºåº•,也就是说, score å€¼æœ€å¤§çš„æˆå‘˜æŽ’名为 0 ã€‚
    * ä½¿ç”¨ ZRANK å‘½ä»¤å¯ä»¥èŽ·å¾—æˆå‘˜æŒ‰ score å€¼é€’增(从小到大)排列的排名。
    */
   public Long zRevrank(String key, Object member) {
      return zSetOps.reverseRank(key, member);
   }
   /**
    * ç§»é™¤æœ‰åºé›† key ä¸­çš„一个或多个成员,不存在的成员将被忽略。
    * å½“ key å­˜åœ¨ä½†ä¸æ˜¯æœ‰åºé›†ç±»åž‹æ—¶ï¼Œè¿”回一个错误。
    */
   public Long zRem(String key, Object... members) {
      return zSetOps.remove(key, members);
   }
   /**
    * è¿”回有序集 key ä¸­ï¼Œæˆå‘˜ member çš„ score å€¼ã€‚
    * å¦‚æžœ member å…ƒç´ ä¸æ˜¯æœ‰åºé›† key çš„æˆå‘˜ï¼Œæˆ– key ä¸å­˜åœ¨ï¼Œè¿”回 nil ã€‚
    */
   public Double zScore(String key, Object member) {
      return zSetOps.score(key, member);
   }
}