范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

进阶篇Redis实战之Jedis使用技巧详解,纯干活

  一、摘要
  在上一篇文章中,我们详细的介绍了 redis 的安装和常见的操作命令,以及可视化工具的介绍。
  刚知道服务端的操作知识,还是远远不够的,如果想要真正在项目中得到应用,我们还需要一个 redis 的客户端,然后将其集成到项目中,让程序自动根据我们的业务需要自动处理。
  基于 redis 开放的通信协议,大神们纷纷开发了各种语言的 redis 客户端,有 c、c++、java、python、php、nodeJs 等等开发语言的客户端,准确来说其实这些客户端都是基于 redis 命令做了一层封装,然后打包成工具以便大家更加方便的操作 redis,以 Java 项目为例,使用最广的就是以下三种客户端:  Jedis  Lettuce  Redisson
  由于篇幅的原因,我们分三篇文章来详细的讲解每个客户端的使用方式以及它的优缺点。
  废话不多说,直奔主题!  二、Jedis
  Jedis 是老牌的 Redis 的 Java 客户端,提供了比较全面的 Redis 命令的操作支持,也是目前使用最广泛的客户端。
  官方网址如下:  https://github.com/redis/jedis
  如何在项目中集成 Jedis 呢?请看下文!  2.1、基本使用
  首先创建一个普通的 Maven 项目,然后添加 Jedis 依赖包!    redis.clients   jedis   3.9.0 
  然后创建一个简单的测试,即可实现连接!  public class JedisMain {      public static void main(String[] args) {         // 1.构造一个 Jedis 对象,因为这里使用的默认端口 6379,所以不用配置端口         Jedis jedis = new Jedis("127.0.0.1", 6379);         // 2.密码认证         jedis.auth("111111");         // 3.测试是否连接成功         String ping = jedis.ping();         // 4.返回 pong 表示连接成功         System.out.println(ping);     } }
  对于 Jedis 而言,一旦连接上了 Redis 服务器,剩下的操作就非常容易了,由于 Jedis 中的 API 和 Redis 的命令高度一致,所以,Jedis 中的方法见名知意,直接使用即可。  2.2、连接池
  虽然 redis 服务端是单线程操作,但是在实际项目中,使用 Jedis 对象来操作 redis 时,每次操作都需要新建/关闭 TCP 连接,连接资源开销很高,同时 Jedis 对象的个数不受限制,在极端情况下可能会造成连接泄漏,同时 Jedis 存在多线程不安全的问题。
  为什么说 Jedis 线程不安全,更加详细的原因可以访问这个地址 https://www.cnblogs.com/gxyandwmm/p/13485226.html !
  所以我们需要将 Jedis 交给线程池来管理,使用 Jedis 对象时,从连接池获取 Jedis,使用完成之后,再还给连接池。
  在使用之前,需要添加 common-pool 线程池依赖包!   org.apache.commons  commons-pool2  2.11.1 
  创建一个简单的使用线程池测试用例。  public class JedisPoolMain {      public static void main(String[] args) {         // 1. 构造一个 Jedis 连接池         JedisPool pool = new JedisPool("127.0.0.1", 6379);         // 2. 从连接池中获取一个 Jedis 连接         Jedis jedis = pool.getResource();         jedis.auth("111111");         // 3. Jedis 操作         String ping = jedis.ping();         System.out.println(ping);         // 4. 归还连接         jedis.close();     } } 2.3、连接池配置
  在实际的使用过程中,我们常常会这样来初始化线程池 JedisPool ,详细代码如下: public class RedisPoolUtils {      private static JedisPool jedisPool = null;      /**      * redis服务器地址      */     private static String addr = "127.0.0.1";      /**      * redis服务器端口      */     private static int port = 6379;      /**      * redis服务器密码      */     private static String auth = "111111";       static{         try {             JedisPoolConfig config = new JedisPoolConfig();             //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true             config.setBlockWhenExhausted(true);             //设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)             config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");             //是否启用pool的jmx管理功能, 默认true             config.setJmxEnabled(true);             //MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默认为"pool", JMX不熟,具体不知道是干啥的...默认就好.             config.setJmxNamePrefix("pool");             //是否启用后进先出, 默认true             config.setLifo(true);             //最大空闲连接数, 默认8个             config.setMaxIdle(8);             //最大连接数, 默认8个             config.setMaxTotal(8);             //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1             config.setMaxWaitMillis(-1);             //逐出连接的最小空闲时间 默认1800000毫秒(30分钟)             config.setMinEvictableIdleTimeMillis(1800000);             //最小空闲连接数, 默认0             config.setMinIdle(0);             //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3             config.setNumTestsPerEvictionRun(3);             //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)             config.setSoftMinEvictableIdleTimeMillis(1800000);             //在获取连接的时候检查有效性, 默认false             config.setTestOnBorrow(false);             //在空闲时检查有效性, 默认false             config.setTestWhileIdle(false);             //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1             config.setTimeBetweenEvictionRunsMillis(-1);             jedisPool = new JedisPool(config, addr, port, 3000, auth);         } catch (Exception e) {             e.printStackTrace();         }     }      /**      * 获取 Jedis 资源      * @return      */     public static Jedis getJedis() {         if (jedisPool != null) {             return jedisPool.getResource();         }         return null;     }      /**      * 释放Jedis资源      */     public static void close(final Jedis jedis) {         if (jedis != null) {             jedis.close();         }     }  }
  简单测试  public static void main(String[] args) throws InterruptedException {     //获取 jedis 客户端     Jedis jedis = RedisPoolUtils.getJedis();      System.out.println("清空数据:"+jedis.flushDB());     System.out.println("判断某个键是否存在:"+jedis.exists("username"));     System.out.println("新增<"username","xmr">的键值对:"+jedis.set("username", "xmr"));     System.out.println(jedis.exists("username"));     System.out.println("新增<"password","password">的键值对:"+jedis.set("password", "123"));     System.out.print("系统中所有的键如下:");     Set keys = jedis.keys("*");     System.out.println(keys);     System.out.println("删除键password:"+jedis.del("password"));     System.out.println("判断键password是否存在:"+jedis.exists("password"));     System.out.println("设置键username的过期时间为5s:"+jedis.expire("username", 8L));     TimeUnit.SECONDS.sleep(1);     System.out.println("查看键username的剩余生存时间:"+jedis.ttl("username"));     System.out.println("移除键username的生存时间:"+jedis.persist("username"));     System.out.println("查看键username的剩余生存时间:"+jedis.ttl("username"));     System.out.println("查看键username所存储的值的类型:"+jedis.type("username"));     RedisPoolUtils.close(jedis); }
  运行结果如下:  清空数据:OK 判断某个键是否存在:false 新增<"username","xmr">的键值对:OK true 新增<"password","password">的键值对:OK 系统中所有的键如下:[password, username] 删除键password:1 判断键password是否存在:false 设置键username的过期时间为5s:1 查看键username的剩余生存时间:7 移除键username的生存时间:1 查看键username的剩余生存时间:-1 查看键username所存储的值的类型:string 2.4、字符串常用 API 操作public class RedisClientUtil {      private static final Logger log = LoggerFactory.getLogger(RedisClientUtil.class);       /**      * 获取指定key的值,如果key不存在返回null      * 返回值:返回 key 的值,如果 key 不存在时,返回 nil      * @param key      * @return      */     public static String get(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.get(key);         } catch (Exception e){             log.error("get命令操作失败,请求参数:{}", key,e);         }         return null;     }       /**      * 设置key的值为value      * 返回值:操作成功完成时返回 OK      * @param key      * @return      */     public static String set(String key, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.set(key, value);         } catch (Exception e){             log.error("set命令操作失败,参数key:{},参数value:{}", key, value,e);         }         return null;     }       /**      * 删除指定的key,返回值:被删除 key 的数量      * 返回值:被删除 key 的数量      * @param key      * @return      */     public static Long del(String key) {         try (Jedis jedis = jedisPool.getResource()) {             Long result = jedis.del(key);             return jedis.del(key);         } catch (Exception e){             log.error("del命令操作失败,参数key:{}", key,e);         }         return 0L;     }       /**      * 通过key向指定的value值追加值      * 返回值:追加指定值之后, key中字符串的长度      * @param key      * @return      */     public static Long append(String key, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.append(key, value);         } catch (Exception e){             log.error("append命令操作失败,参数key:{},参数value:{}", key, value,e);         }         return 0L;     }      /**      * 判断key是否存在      * 返回值:true/false      * @param key      * @return      */     public static Boolean exists(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.exists(key);         } catch (Exception e){             log.error("exists命令操作失败,参数key:{}", key,e);         }         return false;     }       /**      * 设置key的超时时间为seconds      * 返回值:若 key 存在返回 1 ,否则返回 0      * @param key      * @return      */     public static Long expire(String key, long seconds) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.expire(key, seconds);         } catch (Exception e){             log.error("expire命令操作失败,参数key:{},参数seconds:{}", key, seconds,e);         }         return 0L;     }      /**      * 返回 key 的剩余过期时间(单位秒)      * 返回值:当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间      * @param key      * @return      */     public static Long ttl(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.ttl(key);         } catch (Exception e){             log.error("ttl命令操作失败,参数key:{}", key,e);         }         return 0L;     }       /**      * 设置指定key的值为value,当key不存在时才设置      * 返回值:设置成功返回 1,设置失败返回 0      * @param key      * @return      */     public static Long setnx(String key, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.setnx(key, value);         } catch (Exception e){             log.error("setnx命令操作失败,参数key:{},参数value:{}", key, value,e);         }         return 0L;     }      /**      * 设置指定key的值为value,并设置过期时间      * 返回值:设置成功时返回 OK      * @param key      * @return      */     public static String setex(String key, String value, long seconds) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.setex(key, seconds, value);         } catch (Exception e){             log.error("setex命令操作失败,参数key:{},参数value:{}", key, value,e);         }         return null;     }      /**      * 通过key 和offset 从指定的位置开始将原先value替换      * 返回值:被修改后的字符串长度      * @param key      * @return      */     public static Long setrange(String key, int offset, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.setrange(key, offset, value);         } catch (Exception e){             log.error("setrange命令操作失败,参数key:{},参数value:{},参数offset:{}", key, value, offset,e);         }         return null;     }       /**      * 通过批量的key获取批量的value      * 返回值:一个包含所有给定 key 的值的列表。      * @param keys      * @return      */     public static List mget(String... keys) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.mget(keys);         } catch (Exception e){             log.error("mget命令操作失败,参数key:{}", keys.toString(),e);         }         return null;     }      /**      * 批量的设置key:value,也可以一个      * 返回值:总是返回 OK      * @param keysValues      * @return      */     public static String mset(String... keysValues) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.mset(keysValues);         } catch (Exception e){             log.error("mset命令操作失败,参数key:{}", keysValues.toString(),e);         }         return null;     }       /**      * 设置key的值,并返回一个旧值      * 返回值:返回给定 key 的旧值,当 key 没有旧值时,即 key 不存在时,返回 nil      * @param key      * @return      */     public static String getSet(String key, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.getSet(key, value);         } catch (Exception e){             log.error("getSet命令操作失败,参数key:{},参数value:{}", key, value,e);         }         return null;     }      /**      * 通过下标和 key 获取指定下标位置的 value      * 返回值:截取得到的子字符串      * @param key      * @return      */     public static String getrange(String key, int startOffset, int endOffset) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.getrange(key, startOffset, endOffset);         } catch (Exception e){             log.error("getrange命令操作失败,参数key:{},参数startOffset:{},参数offset:{}", key, startOffset, endOffset,e);         }         return null;     }       /**      * 通过key 对value进行加值+1操作,当value不是int类型时会返回错误,当key不存在是则value为1      * 返回值:执行INCR命令之后 key 的值      * @param key      * @return      */     public static Long incr(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.incr(key);         } catch (Exception e){             log.error("incr命令操作失败,参数key:{}", key, e);         }         return 0L;     }       /**      * 通过key给指定的value加值      * 返回值:执行INCR命令之后 key 的值      * @param key      * @return      */     public static Long incrBy(String key, long increment) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.incrBy(key, increment);         } catch (Exception e){             log.error("incrBy命令操作失败,参数key:{},参数increment:{}", key, increment,e);         }         return 0L;     }      /**      * 对key的值做减减操作      * 返回值:执行INCR命令之后 key 的值      * @param key      * @return      */     public static Long decr(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.decr(key);         } catch (Exception e){             log.error("decr命令操作失败,参数key:{}", key, e);         }         return 0L;     }      /**      * 对key的值做减减操作,减去指定的值      * 返回值:执行INCR命令之后 key 的值      * @param key      * @return      */     public static Long decrBy(String key, long decrement) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.decrBy(key, decrement);         } catch (Exception e){             log.error("decrBy命令操作失败,参数key:{},参数decrement:{}", key, decrement,e);         }         return 0L;     }       /**      * 通过key获取value值的长度      * 返回值:value值的长度      * @param key      * @return      */     public static Long strlen(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.strlen(key);         } catch (Exception e){             log.error("strlen命令操作失败,参数key:{}", key, e);         }         return 0L;     } } 2.5、哈希常用 API 操作public class RedisClientUtil {      private static final Logger log = LoggerFactory.getLogger(RedisClientUtil.class);       /**      * 通过key 和 field 获取指定的 value      * 返回值:对应的value值      * @param key      * @return      */     public static String hget(String key, String field) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hget(key, field);         } catch (Exception e){             log.error("hget命令操作失败,参数key:{},参数field:{}", key, field,e);         }         return null;     }      /**      * 通过key给field设置指定的值,如果key不存在,则先创建      * 返回值:如果字段是哈希表中的一个新建字段,并且值设置成功,返回 1 ;如果哈希表中域字段已经存在且旧值已被新值覆盖,返回 0 。      * @param key      * @return      */     public static Long hset(String key, String field, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hset(key, field, value);         } catch (Exception e){             log.error("hset命令操作失败,参数key:{},参数field:{},参数value:{}", key, field, value,e);         }         return 0L;     }       /**      * 通过key和field判断是否有指定的value存在      * 返回值:true/false      * @param key      * @return      */     public static Boolean hexists(String key, String field) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hexists(key, field);         } catch (Exception e){             log.error("hexists命令操作失败,参数key:{},参数field:{}", key, field,e);         }         return false;     }       /**      * 通过key返回field的数量      * 返回值:field的数量      * @param key      * @return      */     public static Long hlen(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hlen(key);         } catch (Exception e){             log.error("hlen命令操作失败,参数key:{}", key,e);         }         return 0L;     }       /**      * 通过key 删除指定的 field      * 返回值:删除的数量      * @param key      * @return      */     public static Long hdel(String key, String... fields) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hdel(key, fields);         } catch (Exception e){             log.error("hdel命令操作失败,参数key:{},参数fields:{}", key, fields.toString(),e);         }         return 0L;     }       /**      * 通过key返回所有的field      * 返回值:field集合      * @param key      * @return      */     public static Set hkeys(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hkeys(key);         } catch (Exception e){             log.error("hkeys命令操作失败,参数key:{}", key,e);         }         return null;     }       /**      * 通过key获取所有的field和value      * 返回值:map对象      * @param key      * @return      */     public static Map hgetAll(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.hgetAll(key);         } catch (Exception e){             log.error("hgetAll命令操作失败,参数key:{}", key,e);         }         return null;     } } 2.6、列表常用 API 操作public class RedisClientUtil {      private static final Logger log = LoggerFactory.getLogger(RedisClientUtil.class);       /**      * 过key向list头部添加字符串      * 返回值:执行 LPUSH 命令后,列表的长度      * @param key      * @return      */     public static Long lpush(String key, String... strs) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lpush(key, strs);         } catch (Exception e){             log.error("lpush命令操作失败,参数key:{},参数strs:{}", key, strs.toString(),e);         }         return null;     }       /**      * 通过key向list尾部添加字符串      * 返回值:执行 RPUSH 命令后,列表的长度      * @param key      * @return      */     public static Long rpush(String key, String... strs) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.rpush(key, strs);         } catch (Exception e){             log.error("rpush命令操作失败,参数key:{},参数strs:{}", key, strs.toString(),e);         }         return null;     }      /**      * 通过key设置list指定下标位置的value 如果下标超过list里面value的个数则报错      * 返回值:操作成功返回 ok ,否则返回错误信息      * @param key      * @return      */     public static String lset(String key, Long index, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lset(key, index, value);         } catch (Exception e){             log.error("lset命令操作失败,参数key:{},参数index:{},参数value:{}", key, index, value,e);         }         return null;     }       /**      * 通过key从对应的list中删除指定的count个 和 value相同的元素      * 返回值:返回被删除的个数      * @param key      * @return      */     public static Long lrem(String key, long count, String value) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lrem(key, count, value);         } catch (Exception e){             log.error("lrem命令操作失败,参数key:{},参数count:{},参数value:{}", key, count, value,e);         }         return null;     }        /**      * 通过key保留list中从strat下标开始到end下标结束的value值      * 返回值:操作成功返回 ok ,否则返回错误信息      * @param key      * @return      */     public static String ltrim(String key, long start, long end) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.ltrim(key, start, end);         } catch (Exception e){             log.error("ltrim命令操作失败,参数key:{},参数start:{},参数end:{}", key, start, end,e);         }         return null;     }       /**      * 通过key从list的头部删除一个value,并返回该value      * 返回值:value值      * @param key      * @return      */     public static String lpop(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lpop(key);         } catch (Exception e){             log.error("lpop命令操作失败,参数key:{}", key,e);         }         return null;     }      /**      * 通过key从list尾部删除一个value,并返回该元素      * 返回值:value值      * @param key      * @return      */     public static String rpop(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.rpop(key);         } catch (Exception e){             log.error("rpop命令操作失败,参数key:{}", key,e);         }         return null;     }       /**      * 通过key获取list中指定下标位置的value      * 返回值:value值      * @param key      * @return      */     public static String lindex(String key, long index){         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lindex(key, index);         } catch (Exception e){             log.error("lindex命令操作失败,参数key:{},参数index:{}", key, index,e);         }         return null;     }       /**      * 通过key返回list的长度      * 返回值:value值      * @param key      * @return      */     public static Long llen(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.llen(key);         } catch (Exception e){             log.error("llen命令操作失败,参数key:{}", key,e);         }         return null;     }       /**      * 通过key获取list指定下标位置的value 如果start 为 0 end 为 -1 则返回全部的list中的value      * 返回值:value值      * @param key      * @return      */     public static List lrange(String key, long start, long end) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.lrange(key, start, end);         } catch (Exception e){             log.error("lrange命令操作失败,参数key:{},参数start:{},参数end:{}", key, start, end,e);         }         return null;     }  } 2.7、集合常用 API 操作public class RedisClientUtil {      private static final Logger log = LoggerFactory.getLogger(RedisClientUtil.class);       /**      * 通过key向指定的set中添加value      * 返回值:添加成功的个数      * @param key      * @return      */     public static Long sadd(String key, String... members)  {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.sadd(key, members);         } catch (Exception e){             log.error("sadd命令操作失败,参数key:{},参数members:{}", key, members.toString(),e);         }         return null;     }      /**      * 通过key删除set中对应的value值      * 返回值:删除成功的个数      * @param key      * @return      */     public static Long srem(String key, String... members)  {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.srem(key, members);         } catch (Exception e){             log.error("srem命令操作失败,参数key:{},参数members:{}", key, members.toString(),e);         }         return null;     }      /**      * 通过key获取set中value的个数      * 返回值:value的个数      * @param key      * @return      */     public static Long scard(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.scard(key);         } catch (Exception e){             log.error("scard命令操作失败,参数key:{}", key,e);         }         return 0L;     }       /**      * 通过key判断value是否是set中的元素      * 返回值:true/false      * @param key      * @return      */     public static Boolean sismember(String key, String member) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.sismember(key, member);         } catch (Exception e){             log.error("sismember命令操作失败,参数key:{},参数member:{}", key, member,e);         }         return false;     }       /**      * 通过key获取set中所有的value      * 返回值:所有的value      * @param key      * @return      */     public static Set smembers(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.smembers(key);         } catch (Exception e){             log.error("smembers命令操作失败,参数key:{}", key,e);         }         return null;     }  } 2.8、有序集合常用 API 操作public class RedisClientUtil {      private static final Logger log = LoggerFactory.getLogger(RedisClientUtil.class);      /**      * 通过key向zset中添加value,score,其中score就是用来排序的 如果该value已经存在则根据score更新元素      * 返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员      * @param key      * @return      */     public static Long zadd(String key, double score, String member) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zadd(key, score, member);         } catch (Exception e){             log.error("zadd命令操作失败,参数key:{},参数score:{},参数member:{}", key, score, member,e);         }         return null;     }       /**      * 通过key删除在zset中指定的value      * 返回值:删除个数      * @param key      * @return      */     public static Long zrem(String key, String... members) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zrem(key, members);         } catch (Exception e){             log.error("zrem命令操作失败,参数key:{},参数members:{}", key, members.toString(),e);         }         return null;     }       /**      * 通过key增加该zset中value的score的值      * 返回值:member 成员的新分数值      * @param key      * @return      */     public static Double zincrby(String key, double score, String member) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zincrby(key, score, member);         } catch (Exception e){             log.error("zincrby命令操作失败,参数key:{},参数score:{},参数member:{}", key, score, member,e);         }         return null;     }      /**      * 通过key返回zset中value的排名 下标从小到大排序      * 返回值:返回 member 的排名      * @param key      * @return      */     public static Long zrank(String key, String member) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zrank(key, member);         } catch (Exception e){             log.error("zrank命令操作失败,参数key:{},参数member:{}", key, member,e);         }         return null;     }       /**      * 通过key将获取score从start到end中zset的value socre从大到小排序 当start为0 end为-1时返回全部      * 返回值:返回 member 集合      * @param key      * @return      */     public static Set zrevrange(String key, long start, long end) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zrevrange(key, start, end);         } catch (Exception e){             log.error("zrevrange命令操作失败,参数key:{},参数start:{},参数end:{}", key, start, end,e);         }         return null;     }      /**      * 返回指定区间内zset中value的数量      * 返回值:返回 member 集合      * @param key      * @return      */     public static Long zcount(String key, String min, String max)  {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zcount(key, min, max);         } catch (Exception e){             log.error("zcount命令操作失败,参数key:{},参数min:{},参数max:{}", key, min, max,e);         }         return null;     }       /**      * 通过key返回zset中的value个数      * 返回值:返回 member 集合      * @param key      * @return      */     public static Long zcard(String key)  {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.zcard(key);         } catch (Exception e){             log.error("zcard命令操作失败,参数key:{}", key,e);         }         return null;     }       /**      * 返回满足pattern表达式的所有key keys(*) 返回所有的key      * 返回值:返回 key 集合      * @param pattern      * @return      */     public static Set keys(String pattern) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.keys(pattern);         } catch (Exception e){             log.error("keys命令操作失败,参数pattern:{}", pattern,e);         }         return null;     }      /**      * 通过key判断值得类型      * 返回值:值的类型      * @param key      * @return      */     public static String type(String key) {         try (Jedis jedis = jedisPool.getResource()) {             return jedis.type(key);         } catch (Exception e){             log.error("type命令操作失败,参数key:{}", key,e);         }         return null;     }  } 三、集群配置
  在实际的项目生产环境中,redis 通常不是以单台服务实例来运行的,因为一旦服务器挂了,可能所有的下游服务都会受到影响,因此为了保障单台服务器即使出现故障也能运行,通常运维组会搭建集群环境,来保证服务高可用。
  搭建的方式有两种,哨兵模式和 Cluster 模式。  哨兵模式:对redis服务器进行监控,如果有宕机的,就从备机里面选一个出来作为主机,实现自动切换  Cluster 模式:将数据进行分片存储,避免全部节点数据都一样,浪费空间  3.1、哨兵模式
  哨兵模式简单的说,就是一台主机,一台备机,外加一台监控服务,当监控服务观测到主机已经宕机,就会将备用机切换成主机,以便继续提供服务。  public class RedisPoolUtils {      private static Jedis jedis;      private static JedisSentinelPool jedisSentinelPool;      static{         try {             JedisPoolConfig config = new JedisPoolConfig();             //最大空闲连接数, 默认8个             config.setMaxIdle(8);             //最大连接数, 默认8个             config.setMaxTotal(8);             //最小空闲连接数, 默认0             config.setMinIdle(0);             //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1             config.setMaxWaitMillis(3000);             //在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false             config.setTestOnBorrow(true);               //redis服务器列表             Set sentinels = new HashSet<>();             sentinels.add(new HostAndPort("192.168.43.212", 26379).toString());             sentinels.add(new HostAndPort("192.168.43.213", 26379).toString());             sentinels.add(new HostAndPort("192.168.43.214", 26379).toString());              //初始化连接池             jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels, config, "111111");             // 从池中获取一个Jedis对象             jedis = jedisSentinelPool.getResource();         } catch (Exception e) {             e.printStackTrace();         }     }      } 3.2、集群模式
  为了保证高可用,redis-cluster集群通常会引入主从复制模型,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。  public class RedisPoolUtils {      static{         try {             JedisPoolConfig config = new JedisPoolConfig();             //最大空闲连接数, 默认8个             config.setMaxIdle(8);             //最大连接数, 默认8个             config.setMaxTotal(8);             //最小空闲连接数, 默认0             config.setMinIdle(0);             //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1             config.setMaxWaitMillis(3000);             //在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false             config.setTestOnBorrow(true);              Set nodes = new HashSet<>();             nodes.add(new HostAndPort("192.168.43.212", 26379));             nodes.add(new HostAndPort("192.168.43.213", 26379));             nodes.add(new HostAndPort("192.168.43.214", 26379));              JedisCluster jedisCluster = new JedisCluster(nodes, config);             jedisCluster.set("key", "hello world");              jedisCluster.close();         } catch (Exception e) {             e.printStackTrace();         }     } } 四、小结
  jedis 客户端是目前使用最广泛的一款 java 客户端,也是老牌的 Redis 的 Java 实现客户端。
  优点很突出:  比较全面的提供了 Redis 的操作特性,也就是说你能用 redis 命令操作的,Jedis 包都也给你封装好了,直接使用即可  使用广泛,易上手
  当然,缺点也有:  Jedis 客户端实例不是线程安全的,需要借助连接池来管理和使用 Jedis  使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到 sockets 处理完 I/O 才能执行,不支持异步
  本文主要是围绕 jedis 客户端做了一次知识总结,希望能帮助到大家,内容难免有所遗漏,欢迎批评指出! 五、参考
  1、redis - 中文文档
  2、腾讯云 - redis几种java客户端比较
  3、runoob - redis教程
  4、简书 - redis java 客户端
  原文链接:https://mp.weixin.qq.com/s/XRRmiWXEgpKmf04Rp48l_Q

风起洛阳又是一部烂尾剧!突现惊天BUG,彻底没救了遥想风起洛阳开播之初,可谓是赞誉之声一片,然而如今却大有烂尾之势。抄袭疑云客观而言,剧情过半时,风起洛阳的口碑已经明显在下滑了。源于一些观众猜到了春秋道的阴谋,利用神都地下的暗涌冲杨鸣怎么看?辽篮弃将同时发威,哈德森41分,西蒙斯大帽广东FMVP北京时间12月28日,下午有两场CBA常规赛同时进行,最终广东99125输给山西山东101102输给四川。抛开结果不谈,这两场比赛有一个共同点,那就是两名辽宁队的外援弃将同时发威,CBA三消息广东输球掉到第七,辽宁第一很稳固,山西跃居第六位爱国篮,爱CBA,我是洛姐,小伙伴们看完记得点赞!在常规赛第一阶段比赛结束的时候,广东队的战绩让球迷们比较满意,当时他们以11胜2负的成绩排在联盟中的第二位,仅次于辽宁队,当时大家天津女排要丢冠?!为什么连续两场30,王宝泉却愁容满面?同津苏之战结果一样,天津队30拿下了上海队。不同的是过程外援休战精锐尽藏,战略性放弃的上海队惊出了天津队一身冷汗,前两局一度打得难分难解!王音迪等一班小将敢打敢拼,发挥可谓惊艳。面CBA前瞻双外援发力,山西力克广东,辽宁胜天津,广厦憾负深圳CBA前瞻双外援发力,山西力克广东,辽宁胜天津,广厦憾负深圳北京时间12月27日,CBA第二阶段第3个比赛日全部结束,今天的两场比赛中,北京首钢队以41分的巨大优势击败同曦队,取得最便宜简单的养生攻略,6招帮你补肾强骨有一句老话说春养肝夏养心秋养肺冬养肾现在是养肾非常好的时机肾补好了,五脏都可受益今天分享给大家最便宜简单的养生攻略6招帮你补肾强骨01保养身体诀窍补肾强骨糊功效黑色入肾,而且含铁量砂糖桔农药果?药水泡大的?砂糖桔如何保存?怎么挑选砂糖桔砂糖桔主产于广东广西,色泽橙黄至橙红,果壁薄,易剥离,以四会黄田镇出产的尤其鲜美而甘甜,含有丰富的维生素C钙纤维质少量蛋白质脂肪以及丰富的葡萄糖果糖蔗糖苹果酸,枸杞酸柠檬酸以及胡萝细纹早发现不要慌,3个方法帮你减少,皮肤光滑,气色红润面对细纹,很多女性朋友都是一筹莫展的样子,毕竟自己一直都在使用着一些护肤品,其实各种皱纹的出现,并不是因为护肤品用得少,或者是用的不好,更多是和自己生活习惯息息相关,像一些不好的行暗影守望重建在即守望先锋半藏走上救赎之路说起源氏和半藏的故事那基本是每个守望先锋玩家都可以如数家珍,当年一段双龙不知道让多少人入坑了这个游戏,进而开始入了这对兄弟的故事的坑。时至今日,这两个英雄也是守望先锋妥妥的流量密码我的世界原来MC还有这些小知识,你都知道多少?我的世界原来MC还有这些小知识,你都知道多少?我的世界是一款非常好玩的沙盒类游戏,游戏玩法多样,可创造性也非常强大,那么关于这款游戏的一些小知识你都知道多少呢?一起来看看吧。十字变肝血越少,梦越多,4味中药补足肝血睡得好先来讲一则医案。话说古代有个读书人,因为长时间埋头苦读,身子一天一天差了下来,到了晚上觉也睡不好,接二连三地做梦,能连着做一宿,第二天起来呵欠连连,哪还有心思读书?这人呢也倔,就自
悬念揭晓,中国男篮后卫线变动,孙铭徽领衔,2人或成隐患随着中国男篮多人感染新冠,6人滞留在澳大利亚,对于杜锋,也是紧急征召了5位球员,分别是高诗岩翟晓川姜伟泽贺希宁和范子铭。这番亚洲杯赛事,郭艾伦赵继伟周琦是赶不上了,他们至少需要5天晚上21点!中国男排主帅最新采访引争议,球迷吐槽太丢人了北京时间7月9日晚上21点,中国排球传来最新消息,日前,男排主帅吴胜接受央视采访时谈到了球队在世联赛的表现,他表示中国男排和波兰的比赛打出了水平,而这样的表态也引发了很多的争议。吴中国男排四连败,怪主教练?有点冤国家队一输球,就有人说主教练下课!在国内一直存在感不强的中国男排,原来一直在默默地成长着,现在也面临着类似的压力因为疫情原因,各类大赛较少,很多人不知不觉关注到了最近在参加世界联赛iPhone14的配置与价格曝光!再次涨价最新消息,近日有爆料达人晒出了两个Pro版本的核心规格以及售价信息。全新iPhone14Pro和iPhone14ProMax将采用6。16。7英寸120HzOLED显示屏,搭载全新3000元左右的vivo和oppo次旗舰手机你会更喜欢哪一个呢在中国的手机市场中,VIVO和OPPO手机可以说是国内手机的两匹黑马,在国内的市场拥有着较重的市场份额,并且在消费者的眼中也是拥有着不错的口碑。vivo和oppo一直被称作蓝绿厂兄意料之外!印象笔记发布大屏电纸书EverPAPER,预装微信读书Hello,大家好,我是静读君。好家伙,静读君刚发完大屏电纸书的选购指南没多久,一款大屏电纸书就发布了。这款大屏智能本由印象笔记推出,名为印象智能本EverPAPER,于6月28号iPhone14价格贵到离谱,库克精明到骨子里文机sir随着时间的推移,关于iPhone14系列的爆料也是越来越密集。根据此前外界传出的消息,iPhone14系列尤其是Pro机型将迎来较为明显的改变和提升。首先,每年在6月份之6月安卓手机性价比榜出炉五个价位,小米均无缘第一如今的手机市场已经来到7月,对于消费者来说,已经开启了新一轮的换机时刻,只因为接下来的新机非常多,那么想从中挑选出一款适合自己的新机,自然是非常困难。不过,也有很多用户喜欢选择性价中国手机厂商数百亿投资喂不饱印度,小米与vivo被刁难对于印度市场,中国厂商可谓又爱又恨。爱,是因为这个市场足够大,14亿人口,规模跟中国差不多,蕴含着较多的市场机会恨,是这个市场套路太多,不按规则出牌,当你做得红红火火时,说不定那一小米12SUItra民间评测,这一次小米凉下来了,更加贴近高端了小米12SUItra终于取代了小米11UItra,成为了目前小米最为强悍的旗舰手机,而且这次还联名了徕卡,大幅升级了影像体验,所以小米12SUItra体验到底如何?作为先行者,使用朋友圈日常简短文案1臂事少心情好。2和考试和解。3别管了千玺说好看所以就发了。4陈让说笑一个吧。5还会一起吹风吗。6把负面情绪调成静音模式。7今天见了想见的人。8过了期的照片。9想得太仔细了才会有坏