[TOC]
0x00 前言 描述:Redis是一个开源的Key-Value数据缓存,和Memcached类似。现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。
Redis多种类型的value,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。
Jedis 是 Redis 官方首选的 Java 客户端开发包,其他我们有shardjedis可以进行备选;
环境准备: 开始在 Java 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 Java redis 驱动,且你的机器上能正常使用 Java。
0x01 基础语法 描述:主要列举了Jedis中常用的方法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 Jedis jedis = new Jedis ("localhost" ,6379); jedis.auth("password" ); jedis.connect(); jedis.ping(); jedis.disconnect(); jedis.select(1); jedis.set("Key" ,"Value" ); jedis.setex("foo" , 5, "tor" ); jedis.get("Key" ); Set<String> keys = jedis.keys("*" ); Set<String> keys = jedis.keys("key" ); jedis.exists("key1" ); jedis.expire("key1" , 5); jedis.persist("key1" ); jedis.type("key1" ); jedis.rename("key1" , "key2" ); jedis.del("key1" ,"key2" ,"key3" ,"key4" ,"key5" ); jedis.dbSize(); jedis.flushAll(); jedis.lpush("ListKey1" ,"Value0" ); jedis.lpush("ListKey1" ,"Value1" ); jedis.llen("key1" ) List<String> list = jedis.lrange("ListKey1" , 0 ,2); for (int i=0;i<list.size();i++){ System.out.println(list.get(i)); } jedis.hset("hashkey1" , "field1" , "field1-value" ); jedis.hset("hashkey1" , "field2" , "field2-value" ); Map<String,String> map = new HashMap<String,String>(); map.put("field1" , "field1-value" ); map.put("field2" , "field2-value" ); jedis.hmset("hkey1" , map); jedis.hkeys("key1" ); jedis.hvals("key1" ); jedis.hget("hkey1" , "field1" ); Map<String,String> map = jedis.hgetAll("hashkey1" ); for (Map.Entry entry: map.entrySet()) { System.out.print(entry.getKey() + ":" + entry.getValue() + "\t" ); } jedis.hexists("key1" , "field1" ); jedis.hdel("key1" , "field1" ,"field2" ); jedis.sadd("key1" , "value0" ); jedis.sadd("key1" , "value1" ); jedis.sismember("key1" , "value2" )); jedis.scard("key1" ); Set set = jedis.smembers("key1" ); for (Object val : set ) { System.out.println(val); } jedis.sinter("key1" ,"key2" ) jedis.sunion("key1" ,"key2" ) jedis.sdiff("key1" ,"key2" ); jedis.srem("key1" , "value1" ); jedis.set("count" ,"1" ) System.out.println("incr key = " + jedis.incr("count" )); System.out.println("incrby key 5 = " + jedis.incrBy("count" , 5));
0x02 实际案例 描述: 采用Jedis连接Redis数据库的基础使用案例
Redis连接认证配置文件:config.properties1 2 3 RedisUrl=10.20.10.248:6379 RedisAuth=weiyigeek.top
示例1.基础语法使用1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 package top.weiyigeek.connredis;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Set;import redis.clients.jedis.Jedis;public class RedisDemo1 { public static void main (String[] args) { String[] RedisUrl=null ; String RedisAuth=null ; try { Properties prop = new Properties(); InputStream ins = RedisDemo1.class.getClassLoader().getResourceAsStream("config.properties" ); prop.load(ins); RedisUrl=prop.getProperty("RedisUrl" ).split(":" ); RedisAuth=prop.getProperty("RedisAuth" ); System.out.println("RedisServer:" + prop.getProperty("RedisUrl" ) + "\nPassword:" + RedisAuth ); Jedis jedis = new Jedis(RedisUrl[0 ],Integer.parseInt(RedisUrl[1 ])); System.out.println("正在Redis认证连接..." ); jedis.auth(RedisAuth); System.out.println("服务正在运行: " +jedis.ping()+"\n" ); jedis.select(1 ); String key = "WeiyiGeek" ; jedis.set(key, "www.weiyigeek.top" ); jedis.set("count" , "1" ); jedis.setex("Key" , 60 , "60 Sec" ); System.out.println("当前数据库总键数:" +jedis.dbSize()); if (jedis.exists(key)) { System.out.println("Redis中WeyiGeek键存储的字符串为:" + jedis.get(key)); System.out.println("其类型为 : " + jedis.type(key)); } System.out.println("incr key = " + jedis.incr("count" )); System.out.println("incrby key 5 = " + jedis.incrBy("count" , 5 )); Set<String> keys = jedis.keys("*" ); for (Iterator iterator = keys.iterator(); iterator.hasNext();) { String k = (String) iterator.next(); if (jedis.type(k).equalsIgnoreCase("string" )) { System.out.println(k + " - " + jedis.get(k)); } } System.out.println("" ); RedisListTest(jedis); RedisHashTest(jedis); RedisSetTest(jedis); RedisZsetTest(jedis); jedis.flushAll(); jedis.disconnect(); } catch (IOException e) { e.printStackTrace(); } } public static void RedisListTest (Jedis jedis) { jedis.lpush("site-list" , "WeiyiGeek" ); jedis.lpush("site-list" , "Google" ); jedis.lpush("site-list" , "Taobao" ); System.out.println("列表中元素数量: " + jedis.llen("site-list" )); List<String> list = jedis.lrange("site-list" , 0 , 2 ); for (int i=0 ; i<list.size(); i++) { System.out.println("列表项为: " +list.get(i)); } } public static void RedisHashTest (Jedis jedis) { Map<String, String> map = new HashMap<String, String>(); jedis.hset("hashkey1" , "field1" , "1024" ); jedis.hset("hashkey1" , "field2" , "whoami" ); map.put("field3" ,"This" ); map.put("field4" ,"10.24" ); jedis.hmset("hashkey1" , map); if (jedis.hexists("hashkey1" , "field1" )) { System.out.println("\n返回哈希表中给定field的值:" + jedis.hget("hashkey1" , "field1" )); System.out.println("哈希表所有中field域名称: " + jedis.hkeys("hashkey1" )); System.out.println("哈希表所有中field域的值: " +jedis.hvals("hashkey1" )); } Map <String,String> map1 = jedis.hgetAll("hashkey1" ); for (Map.Entry<String, String> entry: map1.entrySet()) { System.out.println("域:" + entry.getKey() + ", 值: " + entry.getValue()); } } public static void RedisSetTest (Jedis jedis) { jedis.sadd("setkey1" , "Java" ); jedis.sadd("setkey1" , "Python" ); jedis.sadd("setkey2" , "Redis" ); jedis.sadd("setkey2" , "Java" ); jedis.sadd("setkey2" , "Java" ); System.out.println("\nset 集合中setkey2键中元素数量 : " + jedis.scard("setkey2" )); if (!jedis.sismember("setkey1" , "setkey2" )) { Set set = jedis.smembers("setkey2" ); for (Object val : set) { System.out.println(val); } } System.out.println("交集:" + jedis.sinter("setkey1" ,"setkey2" )); System.out.println("并集:" + jedis.sunion("setkey1" ,"setkey2" )); System.out.println("差集:" + jedis.sdiff("setkey1" ,"setkey2" )); } public static void RedisZsetTest (Jedis jedis) { jedis.zadd("Zsetkey" , 0 , "redis" ); jedis.zadd("Zsetkey" , 0 , "java" ); jedis.zadd("Zsetkey" , 1 , "eclipse" ); Map<String, Double> map = new HashMap<String, Double>(); map.put("WeiyiGeek" , 1.0 ); map.put("Weiyi" , 3.0 ); map.put("极客" , 4.0 ); jedis.zadd("Zsetkey" , map); System.out.println("\n有序集合元素个数: " + jedis.zcard("Zsetkey" )); System.out.println("指定集合范围内的元素个数: " + jedis.zcount("Zsetkey" , 0 , 1 )); Set set = jedis.zrangeByScore("Zsetkey" ,0 , 100 ); for (Object val : set) { System.out.println(val); } } }
执行结果:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 RedisServer:10.20.10.248:6379 Password:weiyigeek.top 正在Redis认证连接... 服务正在运行: PONG 当前数据库总键数:3 Redis中WeyiGeek键存储的字符串为:www.weiyigeek.top 其类型为 : string incr key = 2 incrby key 5 = 7 count - 7 WeiyiGeek - www.weiyigeek.top Key - 60 Sec 列表中元素数量: 3 列表项为: Taobao 列表项为: Google 列表项为: WeiyiGeek 返回哈希表中给定field的值:1024 哈希表所有中field域名称: [field1, field3, field2, field4] 哈希表所有中field域的值: [1024, whoami, 10.24, This] 域:field3, 值: This 域:field2, 值: whoami 域:field1, 值: 1024 域:field4, 值: 10.24 set 集合中setkey2键中元素数量 : 2Java Redis 交集:[Java] 并集:[Java, Python, Redis] 差集:[Python] 有序集合元素个数: 6 指定集合范围内的元素个数: 4 java redis WeiyiGeek eclipse Weiyi 极客
weiyigeek.top-Redis
0x03 工具包 Jedis连接池 描述:jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术,在创建时初始化一些连接资源存储到连接池中,使用jedis连接资源时不需要创建,而是从连接池中获取一个资源进行redis的操作,使用完毕后不需要销毁该jedis连接资源,而是将该资源归还给连接池供其他请求使用。
注意事项:
1) Redis连接池建立依赖Jedis与commons-pool2-2.8.0.jar包;
2) JedisPoolConfig继承关系,上面我们说到JedisPoolConfig需要依赖Apache common pool
,其中pool配置依赖 common pool
中的BaseObjectPoolConfig
类中定义了相关属性的缺省值,在JedisPoolConfig中定义了相关的属性; 1 2 3 4 5 6 7 8 JedisPoolConfig -> GenericObjectPoolConfig -> BaseObjectPoolConfig -> Cloneable setTestWhileIdle(); | true setMinEvictableIdleTimeMillis(); | 60000 setTimeBetweenEvictionRunsMillis(); | 30000 setNumTestsPerEvictionRun(); | -1
3) JedisPoolConfig参数一览1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 setJmxEnabled setJmxNameBase(String jmxNameBase) setJmxNamePrefix(String jmxNamePrefix) setLifo(boolean lifo) setMaxIdle(int maxIdle) setMinIdle(int minIdle) setMaxTotal(int maxTotal) setMaxWaitMillis(long maxWaitMillis) setTestOnBorrow(boolean testOnBorrow) setTestOnCreate(boolean testOnCreate) setTestOnReturn(boolean testOnReturn) setTestWhileIdle(boolean testWhileIdle) setBlockWhenExhausted(boolean blockWhenExhausted) setNumTestsPerEvictionRun(int numTestsPerEvictionRun) setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis); setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) setFairness(boolean fairness) setEvictionPolicyClassName(String evictionPolicyClassName) getNumActive()
基础示例1:(单机Redis连接池) jedis.properties1 2 3 4 5 6 7 8 9 10 11 12 13 #Jedis Pool Configure RedisHost=10.20.172.248 RedisPort=6379 RedisAuth=WeiyiGeek.top RedisDBIndex=1 RedisTimeout=20 RedisMaxIdle=50 RedisMinIdle=100 RedisMaxTotal=100 RedisWaitMillis=3000 RedisTestBorrow=true RedisTestReturn=true RedisBlockWhenExhausted=true
/Web/src/top/weiyigeek/utils/RedisPoolUtil.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 package top.weiyigeek.utils;import java.util.ResourceBundle;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;public class RedisPoolUtil { private static JedisPool jedisPool; private static String host; private static Integer port; private static String auth; private static Integer dbindex; private static Integer timeout; private static Integer maxIdle; private static Integer minIdle; private static Integer maxTotal; private static Integer maxWaitMillis; private static Boolean testOnBorrow; private static Boolean testOnReturn; private static Boolean blockWhenExhausted; static { ResourceBundle rb = ResourceBundle.getBundle("jedis" ); host = rb.getString("RedisHost" ); port = Integer.parseInt(rb.getString("RedisPort" )); auth = rb.getString("RedisAuth" ); dbindex = Integer.parseInt(rb.getString("RedisDBIndex" )); timeout = Integer.parseInt(rb.getString("RedisTimeout" )); maxIdle = Integer.parseInt(rb.getString("RedisMaxIdle" )); minIdle = Integer.parseInt(rb.getString("RedisMinIdle" )); maxTotal = Integer.parseInt(rb.getString("RedisMaxTotal" )); maxWaitMillis = Integer.parseInt(rb.getString("RedisWaitMillis" )); testOnBorrow = Boolean.parseBoolean(rb.getString("RedisTestBorrow" )); testOnReturn = Boolean.parseBoolean(rb.getString("RedisTestReturn" )); blockWhenExhausted = Boolean.parseBoolean(rb.getString("RedisBlockWhenExhausted" )); } static { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxIdle(maxIdle); poolConfig.setMaxTotal(maxTotal); poolConfig.setMaxWaitMillis(maxWaitMillis); poolConfig.setTestOnBorrow(testOnBorrow); poolConfig.setTestOnReturn(testOnReturn); poolConfig.setBlockWhenExhausted(blockWhenExhausted); jedisPool = new JedisPool(poolConfig, host, port, timeout, auth, dbindex); } public static Jedis getJedis () { System.out.println("当前Redis连接池被使用的数量: " +(jedisPool.getNumActive()+1 )); return jedisPool.getResource(); } public static void close (Jedis jedis) { if (jedis!=null ) jedis.close(); } }
Jedis之Dao类 描述:此处是在于数据库交付操作层进行实现的工具类,只是一部分实现功能,其他功能等遇到的时候在进行补充添加;
/Web/src/top/weiyigeek/connredis/RedisDemo3.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 package top.weiyigeek.connredis;import java.util.Collection;import java.util.Iterator;import java.util.List;import java.util.Set;import redis.clients.jedis.Jedis;public class RedisDemo3 { public final static int EXRP_HOUR = 60 * 60 ; public final static int EXRP_DAY = 60 * 60 * 24 ; public final static int EXRP_MONTH = 60 * 60 * 24 * 30 ; public enum GetValue { LIST(){ @Override public String getValue (Jedis jedis,String key) { List<String> list = jedis.lrange(key, 0 , jedis.llen(key)); return "key=" +key+"|type=list|value=" +toString(list); } }, HASH(){ @Override public String getValue (Jedis jedis, String key) { Set<String> keys = jedis.hkeys(key); return "key=" +key+"|type=hash|value=" +toString(keys); } }, SET(){ @Override public String getValue (Jedis jedis, String key) { Set<String> smembers = jedis.smembers(key); return "key=" +key+"|type=set|value=" +toString(smembers); } }, STRING(){ @Override public String getValue (Jedis jedis, String key) { return "key=" +key+"|type=string|value=" +jedis.get(key); } }, ZSET(){ @Override public String getValue (Jedis jedis, String key) { Set<String> keys = jedis.zrange(key, 0 , jedis.zcard(key)); return "key=" +key+"|type=zset|value=" +toString(keys); } }; public abstract String getValue (Jedis jedis,String key) ; String toString (Collection<String> collection) { StringBuilder sb = new StringBuilder(); Iterator<String> iterator = collection.iterator(); while (iterator.hasNext()){ sb.append(iterator.next()).append("," ); } return sb.substring(0 ,sb.length()-1 ); } } public static boolean exits (Jedis jedis, String key) { return jedis.exists(key); } public static String type (Jedis jedis, String key) { return jedis.type(key); } public static void expire (String key, final int seconds) { } public static boolean del (Jedis jedis, String key) { try { if (jedis.exists(key)) { jedis.del(key); return true ; }else { return false ; } }catch (Exception e) { return false ; } } public static void setKeyString (Jedis jedis, String key, String value, int seconds) throws Exception { try { value = (value == null ||value.isEmpty()) ? "" :value; jedis.setex(key, seconds, value); } catch (Exception e) { throw new Exception("Setting Key Error...." ); } } public static String getKeyString (Jedis jedis, String key) { if (jedis == null || !jedis.exists(key)) { return null ; } return jedis.get(key); } }
使用示例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package top.weiyigeek.connredis;import redis.clients.jedis.Jedis;import top.weiyigeek.utils.RedisPoolUtil;public class RedisDemo2 { public static void main (String[] args) { Jedis redis1 = RedisPoolUtil.getJedis(); System.out.println(redis1.ping()); Jedis redis2 = RedisPoolUtil.getJedis(); System.out.println(redis2.ping()); Jedis redis = null ; int loop = 1 ; while (loop < 3 ) { try { long start = System.currentTimeMillis(); redis = RedisPoolUtil.getJedis(); redis.set("k" +loop, "WeiyiGeek" +loop); String ret = redis.get("k" +loop); long end = System.currentTimeMillis(); System.out.printf("Get ret from redis: %s with %d millis\n" , ret, end-start); } finally { if (redis != null ) { redis.close(); } } loop++; } System.out.println(RedisDemo3.GetValue.STRING.getValue(redis, "Name" )); System.out.println(RedisDemo3.GetValue.LIST.getValue(redis, "site-list" )); System.out.println(RedisDemo3.GetValue.HASH.getValue(redis, "hashkey1" )); System.out.println(RedisDemo3.GetValue.SET.getValue(redis, "setkey1" )); System.out.println(RedisDemo3.GetValue.ZSET.getValue(redis, "Zsetkey" )+"\n" ); long start = System.currentTimeMillis(); try { RedisDemo3.setKeyString(redis, "Name" , "WeiyiGeek" , 360 ); } catch (Exception e) { e.printStackTrace(); } String value = RedisDemo3.getKeyString(redis, "Name" ); long end = System.currentTimeMillis(); System.out.printf("Get ret from redis: %s with %d millis\n" , value, end-start); RedisDemo3.expire("Name" , 3600 ); System.out.println("key值是否存在 = " + RedisDemo3.exits(redis, "hashkey1" )); System.out.println("key值类型 = " +RedisDemo3.type(redis, "hashkey1" )); System.out.println("删除指定Key值状态 = " + RedisDemo3.del(redis, "hashkey1" )); } }
执行结果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 当前Redis连接池被使用的数量: 1 PONG 当前Redis连接池被使用的数量: 2 PONG 当前Redis连接池被使用的数量: 3 Get ret from redis: WeiyiGeek1 with 2 millis 当前Redis连接池被使用的数量: 3 Get ret from redis: WeiyiGeek2 with 11 millis key=Name|type=string|value=WeiyiGeek key=site-list|type=list|value=Taobao,Google,WeiyiGeek key=hashkey1|type=hash|value=Love,Name key=setkey1|type=set|value=Python,Java key=Zsetkey|type=zset|value=java,redis,WeiyiGeek,eclipse,Weiyi,极客 Get ret from redis: WeiyiGeek with 6 millis key值是否存在 = true key值类型 = hash 删除指定Key值状态 = true
Jedis订阅与发布实现 描述:Redis通过publish和subscribe命令实现订阅和发布的功能。
订阅者可以通过subscribe向redis server订阅自己感兴趣的消息类型, redis将信息类型称为通道(channel)
。
当发布者通过publish命令向redis server发送特定类型的信息时,订阅该消息类型的全部订阅者都会收到此消息。
基础示例: Redis驱动包提供了一个抽象类JedisPubSub
继承这个类就完成了对客户端对订阅的监听
/Web/src/top/weiyigeek/utils/RedisPubSubListener.java1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 package top.weiyigeek.utils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import redis.clients.jedis.JedisPubSub;public class RedisPubSubListener extends JedisPubSub { private static final Logger logger = LoggerFactory.getLogger(RedisPubSubListener.class); @Override public void unsubscribe () { super .unsubscribe(); } @Override public void unsubscribe (String... channels) { super .unsubscribe(channels); } @Override public void subscribe (String... channels) { super .subscribe(channels); } @Override public void psubscribe (String... patterns) { super .psubscribe(patterns); } @Override public void punsubscribe () { super .punsubscribe(); } @Override public void punsubscribe (String... patterns) { super .punsubscribe(patterns); } @Override public void onMessage (String channel, String message) { logger.info("onMessage: channel[{}], message[{}]" ,channel, message); } @Override public void onPMessage (String pattern, String channel, String message) { logger.info("onPMessage: pattern[{}], channel[{}], message[{}]" , pattern, channel, message); } @Override public void onSubscribe (String channel, int subscribedChannels) { logger.info("onSubscribe: channel[{}], subscribedChannels[{}]" , channel, subscribedChannels); } @Override public void onUnsubscribe (String channel, int subscribedChannels) { logger.info("channel:{} is been subscribed:{}" , channel, subscribedChannels); } @Override public void onPSubscribe (String pattern, int subscribedChannels) { logger.info("onPSubscribe: pattern[{}], subscribedChannels[{}]" , pattern, subscribedChannels); } public void onPUnsubscribe (String pattern, int subscribedChannels) { logger.info("onPUnsubscribe: pattern[{}], subscribedChannels[{}]" , pattern, subscribedChannels); } }
基础示例:订阅者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package top.weiyigeek.connredis;import org.junit.jupiter.api.Test;import redis.clients.jedis.Jedis;import top.weiyigeek.utils.RedisPoolUtil;import top.weiyigeek.utils.RedisPubSubListener;public class RedisSub { @Test public void sub () { System.out.println("--------订阅者------------------- " ); Jedis jedis = RedisPoolUtil.getJedis(); try { RedisPubSubListener rpsl = new RedisPubSubListener(); jedis.psubscribe(rpsl,"news.*" ); } catch (Exception e) { e.printStackTrace(); } finally { if (jedis != null ) jedis.close(); } } }
基础示例:发布者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package top.weiyigeek.connredis;import org.junit.Test;import redis.clients.jedis.Jedis;import top.weiyigeek.utils.RedisPoolUtil;public class RedisPub { @Test public void Pub () { System.out.println("-------发布者------------- " ); Jedis jedis = RedisPoolUtil.getJedis(); try { jedis.publish("news.share" , "WeiyiGeek-个人分享" ); Thread.sleep(2000 ); jedis.publish("news.blog" , "WeiyiGeek-个人博客" ); Thread.sleep(1000 ); jedis.publish("new" , "最新信息" ); } catch (Exception e) { e.printStackTrace(); } finally { if (jedis != null ) jedis.close(); } } }
执行结果: 此时当在有客户端向new.share或者new.blog通道publish消息时jedis.publish(channel, message)
,onMessage方法即可被触发。1 2 3 4 5 6 7 8 9 [main] INFO top.weiyigeek.utils.RedisPubSubListener - onPSubscribe: pattern[news.*], subscribedChannels[1] [main] INFO top.weiyigeek.utils.RedisPubSubListener - onPMessage: pattern[news.*], channel[news.blog], message[www.weiyigeek.top] [main] INFO top.weiyigeek.utils.RedisPubSubListener - onPMessage: pattern[news.*], channel[news.share], message[WeiyiGeek-个人分享] [main] INFO top.weiyigeek.utils.RedisPubSubListener - onPMessage: pattern[news.*], channel[news.blog], message[WeiyiGeek-个人博客] 当前Redis连接池被使用的数量: 0
借鉴参考:
0x04 入坑解决 0) 针对Redis实例JedisPool提示JedisPoolConfig报错问题 答:在进行测试Redis连接池的使用时候,jedisPoolConfig无补充方法且报启动错误信息org.apache.commons.pool2
; 解决办法:
1.Apache中下载Commons.pool2.jar包然后导入添加到工程里面;
1) 回收函数returnResource弃用说明 答:其中有个函数returnResource已经deprecated了,现在Jedis的close方法重写了,用Jedis.close来释放资源。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Override @Deprecated public void returnResource (final Jedis resource) { if (resource != null ) { try { resource.resetState(); returnResourceObject(resource); } catch (Exception e) { returnBrokenResource(resource); throw new JedisException("Could not return the resource to the pool" , e); } } } @Override public void close () { if (dataSource != null ) { if (client.isBroken()) { this .dataSource.returnBrokenResource(this ); } else { this .dataSource.returnResource(this ); } } else { client.close(); } }
2) 在订阅与发布进行日志输出的时候slf4j的jar包导入错误导致不支持logger.info方法 描述:slf4j-simple-1.7.9下载地址 然后导包到工程之中;1 2 3 4 5 import org.slf4j.Logger;import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(RedisPubSubListener.class); logger.info("onMessage: channel[{}], message[{}]" ,channel, message);
0x05 补充案例 SpringCloud 框架Until包:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import org.springframework.beans.factory.annotation.Value;import org.springframework.cache.annotation.CachingConfigurerSupport;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig; @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Value ("${spring.redis.database}" ) private int index; @Value ("${spring.redis.host}" ) private String host; @Value ("${spring.redis.port}" ) private int port; @Value ("${spring.redis.timeout}" ) private int timeout; @Value ("${spring.redis.pool.max-idle}" ) private int maxIdle; @Value ("${spring.redis.pool.max-wait}" ) private long maxWaitMillis; @Value ("${spring.redis.password}" ) private String password; @Bean public JedisPool redisPoolFactory () { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password,index); return jedisPool; } }
基础示例: redis配置
1 2 3 4 5 6 7 redis.info=192.168.127.128:6379,192.168.127.128:6380 redis.pool.maxTotal=50 redis.pool.maxIdle=20 redis.pool.minIdle=10 redis.pool.maxWaitMillis=1000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Component @Data @PropertySource("config/properties" ) public class RedisConfig { @Value("${redis.info} " ) private String redisInfo; @Value("${redis.pool.maxTotal} " ) private int maxTotal; @Value("${redis.pool.maxIdle} " ) private int maxIdle; @Value("${redis.pool.minIdle} " ) private int minIdle; @Value("${redis.pool.maxWaitMillis} " ) private int maxWaitMillis; }
shardjedis采用一致hash算法实现key的分片,通过计算key的hash值将key分布到不同的redis服务器上,从而达到横向扩展的目的。 以下介绍shardjedis的常用操作。
配置shardjedispool1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Configuration @ComponentScan(basePackages = "config" ) public class ShardJedisPool { @Autowired RedisConfig redisConfig; /** *获取jedisinfo信息 * @return */ private List<JedisShardInfo> jedisShardInfos (){ String[] redisInfos = redisConfig.getRedisInfo().split("," ); List<JedisShardInfo> jedisShardInfos = new ArrayList<>(); for (String redisInfo :redisInfos){ String[] part = redisInfo.split(":" ); jedisShardInfos.add(new JedisShardInfo(part[0],Integer.parseInt(part[1]))); } return jedisShardInfos; } /** * 设置redis的参数配置 * @return */ @Bean public GenericObjectPoolConfig genericObjectPoolConfig (){ GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig(); genericObjectPoolConfig.setMaxIdle(redisConfig.getMaxIdle()); genericObjectPoolConfig.setMaxTotal(redisConfig.getMaxTotal()); genericObjectPoolConfig.setMinIdle(redisConfig.getMinIdle()); genericObjectPoolConfig.setMaxWaitMillis(redisConfig.getMaxWaitMillis()); return genericObjectPoolConfig; } /** * 获取shardjedis连接池 * @param genericObjectPoolConfig * @return */ @Bean public ShardedJedisPool shardedJedisPool(GenericObjectPoolConfig genericObjectPoolConfig){ return new ShardedJedisPool(genericObjectPoolConfig,jedisShardInfos()); }
常用方法:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 @Component public class JedisAction { @Autowired private ShardedJedisPool shardedJedisPool; /** * 获取string类型的value * @param key * @return */ public String get(String key){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()) { return shardedJedis.get(key); } } /** * 设置string类型的值 * @param key * @param value */ public void set (String key,String value){ try (ShardedJedis shardedJedis = shardedJedisPool.getResource()){ shardedJedis.set(key,value); } } /** * 删除key * @param key */ public void del(String key){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ shardedJedis.del(key); } } /** * 判断key是否存在 * @param key * @return */ public boolean exits(String key){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ return shardedJedis.exists(key); } } /** * 获取key的类型 * @param key * @return */ public String type (String key){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ return shardedJedis.type(key); } } /** * 设置key的过期时间 * @param key * @param seconds */ public void expire(String key,final int seconds){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ shardedJedis.expire(key,seconds); } } /** * 根据key的模糊类型获取所有的key * @param pattern * @return */ public List<String> keys(String pattern){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ Collection<Jedis> allShards = shardedJedis.getAllShards(); List<String> keyList = new ArrayList<>(); for (Jedis jedis:allShards){ Set<String> keys = jedis.keys(pattern); keyList.addAll(keys); } return keyList; } } /** * 获取所有匹配模糊key的value值 * @param pattern * @return */ public List<String> getValues(String pattern){ try(ShardedJedis shardedJedis = shardedJedisPool.getResource()){ Collection<Jedis> allShards = shardedJedis.getAllShards(); List<String> values = new ArrayList<>(); for (Jedis jedis:allShards){ Set<String> keys = jedis.keys(pattern); for (String key:keys){ values.add(getValue(jedis,key)); } } return values; } } /** * 不区分key的类型获取key的value,可以匹配string,list,hash ,set 四种类型 * @param jedis * @param key * @return */ public String getValue(Jedis jedis,String key){ String type = jedis.type(key); GetValue value = GetValue.valueOf(type.toUpperCase()); return value.getValue(jedis,key); } }
jedisCluster连接redis(集群) 描述:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Test public void testJedisCluster()throws Exception{ //创建jedisCluster对象,有一个参数 nodes是Set类型,Set包含若干个HostAndPort对象 Set<HostAndPort> nodes = new HashSet<>(); nodes.add(new HostAndPort("192.168.241.133" ,7001)); nodes.add(new HostAndPort("192.168.241.133" ,7002)); nodes.add(new HostAndPort("192.168.241.133" ,7003)); nodes.add(new HostAndPort("192.168.241.133" ,7004)); nodes.add(new HostAndPort("192.168.241.133" ,7005)); nodes.add(new HostAndPort("192.168.241.133" ,7006)); JedisCluster jedisCluster = new JedisCluster(nodes); //使用jedisCluster操作redis jedisCluster.set("test" , "my forst jedis" ); String str = jedisCluster.get("test" ); System.out.println(str); //关闭连接池 jedisCluster.close(); } JedisCluster设置密码 1. 修改配置文件,通过requirePass指定密码 2. 通过JedisCluster构造方法指定密码 new JedisCluster(node, connectionTimeout, soTimeout, maxAttempts, password, poolConfig) new JedisCluster(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, poolConfig)