【 Redis 】
本文介绍一些Redis基础原理,以及命令操作,最后用Java实现Redis消息队列
1.为什么使用Redis
①性能:对于对于执行耗时特别久,且结果不频繁变动的sql特别适合将结果放入缓存。后面的请求就去缓存中读取,使得请求能够迅速响应
②并发:在大并发情况下,所有请求直接访问数据库,数据库会出现连接异常,这时候需要使用redies做一个缓冲让请求先访问到redis
2、使用redis有什么缺点
①缓存和数据库双写一致性问题
②缓存雪崩问题
③缓存击穿问题:缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
④缓存的并发竞争问题
3、单线程的redis为什么这么快
①纯内存操作
②单线程操作,避免了频繁的上下文切换
③采用了非阻塞I/O多路复用机制(多路复用机制如下图,在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流,
单个线程通过记录跟踪每一个Sock(I/O流)的状态)
![](https://img2018.cnblogs.com/blog/1637876/201904/1637876-20190409145602857-1278854287.png)
4、redis的数据类型,以及每种数据类型的使用场景
一共五种数据类型
①String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
②hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
③list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适---取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
④set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
⑤sorted set
sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
5、redis的过期策略以及内存淘汰机制
redis采用的是定期删除+惰性删除策略
定期删除:redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取 进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。
在redis.conf中有一行配置
# maxmemory-policy volatile-lru
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。依然不推荐
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。不推荐
6、redis和数据库双写一致性问题
分析:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。
首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列
7、如何应对缓存穿透和缓存雪崩问题
8、如何解决redis的并发竞争问题
不推荐使用redis的事务机制。因为我们的生产环境,基本都是redis集群环境,做了数据分片操作。你一个事务中有涉及到多个key操作的时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。
(1)如果对这个key操作,不要求顺序
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。
(2)如果对这个key操作,要求顺序
假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.
期望按照key1的value值按照 valueA–>valueB–>valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下
系统
A key 1 {valueA 3:00}
系统
B key 1 {valueB 3:05}
系统
C key 1 {valueC 3:10}
那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。
【密码设置】
config set requirepass songtao0404
auth password
【redis.conf】
daemonize yes #redis后台运行
appendonly yes #开启aof日志,它会每次写操作都记录一条日志
bind 192.168.1.207
使用 redis-server redis.conf
【Redis】
1.redis-cli shutdown //关闭服务
2.redis-server redis.conf //启动服务
3.如果设置了密码,可以连接但是没有权限。需要命令 auth password
4.redis是key-value的数据,所以每个数据都是一个键值对键的类型是字符串
值的类型分为五种: ①字符串string
②哈希hash:是一个string类型的field和value的映射表,hash特别适合用于存储对象。
③列表list
④集合set:无序集合,元素唯一不重复
⑤有序集合zset
5.Redis 单个命令是原子操作
6.Redis命令
字符串:
1. SET key value //设置指定Key的值
2.GET key //获取指定Key的值
3.
GETRANGE key start end //获取key 中字符串值得子字符
4.GETSET key value //将给定key的 值设为value 并返回旧的key 对应的值
5.MGET key1,key,2 //获取多个键对应的值
6.SETEX KEY SECONDS VALUE //给键和值设定失效时间
7.SETNX KEY VALUE //只有在Key不存在时设置值
8.SETRANGE KEY OFFSET VALUE //将key对赢得字符串从偏移量offset处开始用字符串value 覆盖
9.STRLEN KEY //返回KEY所存储的字符串值得长度
10.MSET KEY1 "VALUE1" KEY2 "VALUE2" //同时设置多个KEY-VALUE 对
11.MSETNX KEY1 "VALUE1" KEY2 "VALUE2" //同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
12.
PSETEX key milliseconds value //和SETEX 不同之处在于 这个是以毫秒为单位设置过期时间
13.
INCR key // 将KEY中存储的数字值加1
14.INCRBY KEY INCREMENT //将key所存储的值加上指定的值
15.INCRBYFLOAT KEY INCREMENT //将key所存储的值加上浮点增量值
16.DECR KEY //将key中存储的数字值减1
17.APPEND KEY VALUE //将value 值追加到 key 对应的值末尾,key不存在则设置key-value
18.EXPIRE KEY seconds //只对键设置过期时间
哈希:
1.HSET KEY FIELD VALUE //将哈希表中key中的字段Field设置为value
2.HMSET KEY FIELD1 VALUE1 FIELD2 VALUE2 //同时将多个 field-value (域-值)对设置到哈希表 key 中。
3.HGET KEY FIELD //获取Key 中的 Field字段对应的Value值
4.HMGET KEY FIELD1 FIELD2 //获取Key中的多个字段对应的value值
5.HDEL KEY FIELD1 FIELD2 //删除哈希表中一个或多个KEY对应的字段
6.HEXISTS KEY FIELD //查看哈希表KEY中指定的Field是否存在
7.HGETALL KEY //获取在哈希表中指定KEY的所有字段的值
8.HINCRBY KEY FIELD INCREMENT //为哈希表KEY中指定的Field字段的整数值加上增量值
9.HINCRBYFLOAT KEY FIELD INCREMENT //为哈希表KEY中指定的FIELD字段的浮点数值上加上增量值
10.HKEYS KEY //获取KEY对应的所有字段
11.HLEN KEY //获取哈希表中KEY对应的字段数量
12.HVALS KEY //获取哈希表中KEY所对应的所有值
13.HSETNX KEY FIELD VALUE //只有在字段Field不存在时,设置哈希表字段的值
14.HSCAN key cursor [MATCH pattern] [COUNT count] //迭代哈希表中的键值对。
列表:
1.BLPOP KEY TIMEOUT //移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
2.BRPOP KEY TIMEOUT //移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
3.
BRPOPLPUSH source destination timeout //从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
4.LINDEX KEY index //通过索引获取列表中的元素
5.LINSERT KEY BEFORE|AFTER privot value //在列表元素前或者列表元素后插入元素
6.LLEN KEY //获取列表长度
7.LPOP KEY //移除并获取列表第一个元素
8.LPUSH KEY VALUE1 VALUE2 //将一个或多个值插入到列表中
9.LPUSHX KEY VALUE //将值插入到一个已存在的列表头部
10.LRANGE KEY START END //获取列表指定范围内的元素
11.
LREM key count value //移除列表元素
12.LSET KEY INDEX VALUE //通过索引设置列表元素的值,如果索引位置元素存在会被替代
13.LTRIM KEY START STOP //截取列表
14.RPOP KEY //移除列表的最后一个元素,返回值为移除的元素
15.RPOPLPUSH source destination // 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
16.RPUSH KEY VALUE1 VALUE2 //在列表添加一个或多个元素值
17.RPUSHX KEY VALUE //为已存在的列表添加值
无序集合(Set):
1.SADD KEY MEMBER1 MEMBER2 //向集合添加一个或多个元素
2.SCARD KEY //获取集合成员数
3.SDIFF KEY1 [KEY2] //返回给定所有集合的差集
4.SEMEMBERS KEY //返回集合中的所有成员
5.SDIFFSTORE DESTINATION KEY1 KEY2 //返回所有给定集合的差集,并存储在
6.SINTER KEY1 KEY2 //返回给定所有集合的交集
7.SINTERSTORE destination key1 key2 //返回给定所有集合的交集并存储在 destination 中
8.SISMEMBER KEY MEMBER //判断MEMBERS是不是KEY集合中的元素
9.SMOVE source destination member //将member 元素从source 集合移动到destination
10.SPOP key //移除集合并返回集合中一个随机元素
11.SRANDMEMBER KEY COUNT //返回集合中一个或多个随机数
12.SREM KEY member1 member2 ... //移除集合中一个或多个成员
13.SUNION KEY1 KEY2 .. //返回给定所有集合的并集
14.SUNIONSTORE destination KEY1 KEY2 //所有给定集合的并集存储在destination集合中
有序集合:
1.ZADD KEY SCORE1 MEMBER1 SCORE2 MEMBER2 //向有序集合中添加一个或多个成员,以及成员分数
注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素。
2.ZCARD key //返回集合中元素个数
3.ZCOUNT KEY MIN MAX //计算在有序集合中指定区间分数的成员数
4.ZINCRBY KEY increment member //有序集合中对指定成员的分数加上增量 incrementb,并返回增量后的分数
。。。。
发布订阅:
1.SUBSCRIBE CHANNEL1 CHANNEL2 //订阅一个或多个频道的消息
2.UNSUBSCRIBE CHANNEL1 CHANNEL2 //退订一个或多个指定频道
3.PUBSUB CHANNELS //CHANNELS 就是参数,查看订阅与发布系统状态
4.PUBLISH CHANNELS MESSAGE //给指定频道发送消息
5.PUNSUBSCRIBE PATTERN //退订所有给定模式的频道
6.PSUBSCRIBE PATTERN //订阅一个或多个给定模式的频道
REDIS性能测试:
redis-benchmark -n 10000 -q //以下实例同时执行 10000 个请求来检测性能
![](https://img2018.cnblogs.com/blog/1637876/201904/1637876-20190409145550312-1383166080.png)
Redis密码:
1.客户端查看是否设置了密码:(默认 requirepass参数是空的)
CONFIG get requirepass
2.设置密码
CONFIG SET requirepass "songtao0404"
3.密码验证命令
AUTH songtao0404
Redis备份与恢复:
备份:
> SAVE //此命令创建当前数据库备份,在redis 安装目录中创建dump.rdb文件
或
>
BGSAVE //此命令在后台执行
恢复:将生成的dump.rdb考本到安装目录并启动服务即可
获取redis目录命令:CONFIG GET DIR
Java实现Redis消息队列
消息队列介绍以及项目中为什么使用消息队列请参考:https://www.cnblogs.com/linjiqin/p/5720865.html
1.引入Jedis依赖配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!-- Jedis 依赖配置 --> 2 <dependencies> 3 <dependency> 4 <groupId>redis.clients</groupId> 5 <artifactId>jedis</artifactId> 6 <version>3.0.0</version> 7 </dependency> 8 </dependencies>
2.ObjectUtil.java 消息对象和byte[]互转工具类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package redis; 2 3 import java.io.*; 4 /** 5 * 对象和byte[]互转 6 */ 7 public class ObjectUtil { 8 /** 9 * 对象转byte[] 10 * @param obj 11 * @return 12 * @throws IOException 13 */ 14 public static byte[] object2Bytes(Object obj) throws IOException{ 15 ByteArrayOutputStream bo=new ByteArrayOutputStream(); 16 ObjectOutputStream oo=new ObjectOutputStream(bo); 17 oo.writeObject(obj); 18 byte[] bytes=bo.toByteArray(); 19 bo.close(); 20 oo.close(); 21 return bytes; 22 } 23 /** 24 * byte[]转对象 25 * @param bytes 26 * @return 27 * @throws Exception 28 */ 29 public static Object bytes2Object(byte[] bytes) throws Exception{ 30 ByteArrayInputStream in=new ByteArrayInputStream(bytes); 31 ObjectInputStream sIn=new ObjectInputStream(in); 32 return sIn.readObject(); 33 } 34 }
3.Message.java 消息类,需要实现序列化接口,因为要进行网络传输
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package redis; 2 3 import java.io.Serializable; 4 5 public class Message implements Serializable{ 6 7 /** 8 * serialVersionUID适用于Java的序列化机制。简单来说, 9 * Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。 10 * 在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较, 11 * 如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。 12 */ 13 private static final long serialVersionUID = 1967413132568134038L; 14 15 private int id; 16 private String content; 17 18 public Message(int id,String content) { 19 this.id = id; 20 this.content = content; 21 } 22 23 public int getId() { 24 return id; 25 } 26 27 public void setId(int id) { 28 this.id = id; 29 } 30 31 public String getContent() { 32 return content; 33 } 34 35 public void setContent(String content) { 36 this.content = content; 37 } 38 39 40 41 }
4.RedisUtils.java redis操作工具类()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package redis; 2 3 4 import java.io.File; 5 import java.io.IOException; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 import java.util.Set; 10 11 import javax.xml.parsers.DocumentBuilder; 12 import javax.xml.parsers.DocumentBuilderFactory; 13 import javax.xml.parsers.ParserConfigurationException; 14 15 import org.w3c.dom.Document; 16 import org.w3c.dom.NodeList; 17 import org.xml.sax.SAXException; 18 19 import redis.clients.jedis.Jedis; 20 import redis.clients.jedis.JedisPool; 21 import redis.clients.jedis.JedisPoolConfig; 22 23 public class RedisUtils { 24 private static String JEDIS_IP; //redis ip地址 25 private static int JEDIS_PORT; //端口 26 private static String JEDIS_PASSWORD; //密码 27 private static JedisPool jedisPool; 28 29 static { 30 getConfig(); 31 JedisPoolConfig config = new JedisPoolConfig(); 32 //设置最大实例总数 33 config.setMaxTotal(5000); 34 //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例 35 config.setMaxIdle(256); 36 //表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException; 37 config.setMaxWaitMillis(3*1000); 38 //在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的; 39 config.setTestOnBorrow(true); 40 // 在还会给pool时,是否提前进行validate操作 41 config.setTestOnReturn(true); 42 config.setTestWhileIdle(true); 43 config.setMinEvictableIdleTimeMillis(60000L); 44 config.setTimeBetweenEvictionRunsMillis(3000L); 45 config.setNumTestsPerEvictionRun(-1); 46 jedisPool=new JedisPool(config,JEDIS_IP,JEDIS_PORT,60000); 47 } 48 /** 49 * Dom读取jedis xml配置文件 50 * @return 51 */ 52 private static void getConfig(){ 53 HashMap map = new HashMap<String, String>(); 54 55 //初始化Dom对象 56 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 57 try { 58 DocumentBuilder builder = dbf.newDocumentBuilder(); 59 Document dom = builder.parse(new File("jedis.xml")); 60 NodeList nodeList = dom.getElementsByTagName("redisconfig"); 61 NodeList nodeList2 = nodeList.item(0).getChildNodes(); 62 for(int i=0; i < nodeList2.getLength(); i++) { 63 if("ip".equals(nodeList2.item(i).getNodeName())) { 64 JEDIS_IP = nodeList2.item(i).getFirstChild().getNodeValue(); 65 } 66 if("port".equals(nodeList2.item(i).getNodeName())) { 67 JEDIS_PORT = Integer.parseInt(nodeList2.item(i).getFirstChild().getNodeValue()); 68 } 69 if("password".equals(nodeList2.item(i).getNodeName())) { 70 JEDIS_PASSWORD = nodeList2.item(i).getFirstChild().getNodeValue(); 71 } 72 } 73 System.out.println(JEDIS_IP+","+JEDIS_PORT+","+JEDIS_PASSWORD); 74 } catch (ParserConfigurationException e) { 75 // TODO Auto-generated catch block 76 e.printStackTrace(); 77 } catch (SAXException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } catch (IOException e) { 81 // TODO Auto-generated catch block 82 e.printStackTrace(); 83 } 84 } 85 /** 86 * 获取数据 87 * @param key 88 * @return 89 */ 90 public static String getValue(String key) { 91 Jedis jedis = null; 92 String value = null; 93 try { 94 jedis = jedisPool.getResource(); 95 value = jedis.get(key); 96 } catch (Exception e) { 97 // TODO Auto-generated catch block 98 e.printStackTrace(); 99 }finally { 100 //返还到连接池 101 jedis.close(); 102 } 103 return value; 104 } 105 106 public static byte[] get(byte[] key) { 107 byte[] value = null; 108 Jedis jedis = null; 109 try { 110 jedis = jedisPool.getResource(); 111 value = jedis.get(key); 112 } catch (Exception e) { 113 // TODO: handle exception 114 e.printStackTrace(); 115 }finally { 116 //返还到连接池 117 jedis.close(); 118 } 119 return value; 120 } 121 122 /** 123 * 存储数据 124 * @param key 125 * @param value 126 */ 127 public static void set(byte[] key,byte[] value) { 128 Jedis jedis = null; 129 try { 130 jedis = jedisPool.getResource(); 131 jedis.set(key, value); 132 } catch (Exception e) { 133 // TODO: handle exception 134 e.printStackTrace(); 135 }finally { 136 //返还到连接池 137 jedis.close(); 138 } 139 } 140 141 public static void set(String key,String value) { 142 Jedis jedis = null; 143 try { 144 jedis = jedisPool.getResource(); 145 jedis.set(key, value); 146 } catch (Exception e) { 147 // TODO: handle exception 148 e.printStackTrace(); 149 }finally { 150 //返还到连接池 151 jedis.close(); 152 } 153 } 154 155 public static void set(byte[] key,byte[] value,int time) { 156 Jedis jedis = null; 157 try { 158 jedis = jedisPool.getResource(); 159 jedis.setex(key, time, value); 160 } catch (Exception e) { 161 // TODO: handle exception 162 e.printStackTrace(); 163 }finally { 164 jedis.close(); 165 } 166 } 167 168 public static void hset(byte[] key,byte[] field,byte[] value) { 169 Jedis jedis = null; 170 try { 171 jedis = jedisPool.getResource(); 172 jedis.hset(key,field,value); 173 } catch (Exception e) { 174 // TODO: handle exception 175 e.printStackTrace(); 176 }finally{ 177 jedis.close(); 178 } 179 } 180 181 public static void hset(String key,String field,String value) { 182 Jedis jedis = null; 183 try { 184 jedis = jedisPool.getResource(); 185 jedis.hset(key, field,value); 186 187 } catch (Exception e) { 188 // TODO: handle exception 189 e.printStackTrace(); 190 }finally { 191 jedis.close(); 192 } 193 } 194 195 /** 196 * 获取数据 197 * @param args 198 */ 199 public static String hget(String key,String field) { 200 Jedis jedis = null; 201 String value = null; 202 try { 203 jedis.hget(key, field); 204 } catch (Exception e) { 205 // TODO: handle exception 206 e.printStackTrace(); 207 }finally { 208 jedis.close(); 209 } 210 return value; 211 } 212 213 public static byte[] hget(byte[] key,byte[] field) { 214 Jedis jedis = null; 215 byte[] value = null; 216 try { 217 jedis = jedisPool.getResource(); 218 value = jedis.hget(key, field); 219 } catch (Exception e) { 220 // TODO: handle exception 221 e.printStackTrace(); 222 }finally { 223 jedis.close(); 224 } 225 return value; 226 } 227 228 /** 229 * 删除 230 * @param args 231 */ 232 233 public static void hdel(byte[] key,byte[] fields) { 234 Jedis jedis = null; 235 try { 236 jedis = jedisPool.getResource(); 237 jedis.hdel(key, fields); 238 } catch (Exception e) { 239 // TODO: handle exception 240 e.printStackTrace(); 241 }finally { 242 jedis.close(); 243 } 244 } 245 246 public static void hdel(String key,String fields) { 247 Jedis jedis = null; 248 try { 249 jedis = jedisPool.getResource(); 250 jedis.hdel(key, fields); 251 } catch (Exception e) { 252 // TODO: handle exception 253 e.printStackTrace(); 254 }finally { 255 jedis.close(); 256 } 257 } 258 259 /** 260 * 存储REDIS队列 ,顺序存储 261 * @param args 262 */ 263 public static void lpush(byte[] key,byte[] value) { 264 Jedis jedis = null; 265 try { 266 jedis = jedisPool.getResource(); 267 jedis.lpush(key, value); 268 269 } catch (Exception e) { 270 // TODO: handle exception 271 e.printStackTrace(); 272 }finally { 273 jedis.close(); 274 } 275 } 276 /** 277 * 存储REDIS队列,反向存储 278 * @param args 279 */ 280 public static void rpush(byte[] key,byte[] value) { 281 Jedis jedis = null; 282 try { 283 jedis = jedisPool.getResource(); 284 jedis.rpush(key, value); 285 } catch (Exception e) { 286 // TODO: handle exception 287 e.printStackTrace(); 288 }finally { 289 jedis.close(); 290 } 291 } 292 293 /** 294 * Rpoplpush 命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回。 295 * @param key 296 * @param destination 297 */ 298 public static void rpoplpush(byte[] key,byte[] destination) { 299 Jedis jedis = null; 300 try { 301 jedis = jedisPool.getResource(); 302 jedis.rpoplpush(key, destination); 303 } catch (Exception e) { 304 // TODO: handle exception 305 e.printStackTrace(); 306 }finally { 307 jedis.close(); 308 } 309 } 310 311 /** 312 * 获取队列所有数据 313 * @param args 314 */ 315 public static List getList(byte[] key) { 316 List list = null; 317 Jedis jedis = null; 318 try { 319 jedis = jedisPool.getResource(); 320 list = jedis.lrange(key, 0, -1); 321 322 } catch (Exception e) { 323 // TODO: handle exception 324 e.printStackTrace(); 325 }finally { 326 jedis.close(); 327 } 328 return list; 329 } 330 331 /** 332 * 获取队列数据,并删除 333 * @param args 334 */ 335 public static byte[] rpop(byte[] key) { 336 Jedis jedis = null; 337 byte[] value = null; 338 try { 339 jedis = jedisPool.getResource(); 340 value = jedis.rpop(key); 341 } catch (Exception e) { 342 // TODO: handle exception 343 e.printStackTrace(); 344 }finally { 345 jedis.close(); 346 } 347 return value; 348 } 349 350 public static byte[] lpop(byte[] key) { 351 Jedis jedis = null; 352 byte[] value = null; 353 try { 354 jedis = jedisPool.getResource(); 355 value = jedis.lpop(key); 356 } catch (Exception e) { 357 // TODO: handle exception 358 e.printStackTrace(); 359 }finally { 360 jedis.close(); 361 } 362 return value; 363 } 364 365 public static void hmset(Object key,Map hash) { 366 Jedis jedis = null; 367 try { 368 jedis = jedisPool.getResource(); 369 jedis.hmset(key.toString(), hash); 370 } catch (Exception e) { 371 // TODO: handle exception 372 e.printStackTrace(); 373 }finally { 374 jedis.close(); 375 } 376 } 377 378 /** 379 * time 秒 380 * @param key 381 * @param hash 382 * @param time 383 */ 384 public static void hmset(Object key, Map hash , int time) { 385 Jedis jedis = null; 386 try { 387 jedis = jedisPool.getResource(); 388 jedis.hmset(key.toString(), hash); 389 jedis.expire(key.toString(), time); 390 } catch (Exception e) { 391 // TODO: handle exception 392 e.printStackTrace(); 393 }finally { 394 jedis.close(); 395 } 396 } 397 398 public static List hmget(Object key,String... fields) { 399 List result = null; 400 Jedis jedis = null; 401 try { 402 jedis = jedisPool.getResource(); 403 result = jedis.hmget(key.toString(), fields); 404 } catch (Exception e) { 405 // TODO: handle exception 406 e.printStackTrace(); 407 }finally { 408 jedis.close(); 409 } 410 return result; 411 412 } 413 414 public static Set hkeys(String key) { 415 Jedis jedis = null; 416 Set set = null; 417 try { 418 jedis = jedisPool.getResource(); 419 set = jedis.hkeys(key); 420 } catch (Exception e) { 421 // TODO: handle exception 422 e.printStackTrace(); 423 }finally { 424 jedis.close(); 425 } 426 return set; 427 } 428 429 public static List lrange(byte[] key, int from, int to) { 430 List result = null; 431 Jedis jedis = null; 432 try { 433 jedis = jedisPool.getResource(); 434 result = jedis.lrange(key, from, to); 435 436 } catch (Exception e) { 437 //释放redis对象 438 e.printStackTrace(); 439 } finally { 440 //返还到连接池 441 jedis.close(); 442 443 } 444 return result; 445 } 446 public static Map hgetAll(byte[] key) { 447 Map result = null; 448 Jedis jedis = null; 449 try { 450 jedis = jedisPool.getResource(); 451 result = jedis.hgetAll(key); 452 } catch (Exception e) { 453 //释放redis对象 454 e.printStackTrace(); 455 } finally { 456 //返还到连接池 457 jedis.close(); 458 } 459 return result; 460 } 461 462 public static void del(byte[] key) { 463 464 Jedis jedis = null; 465 try { 466 jedis = jedisPool.getResource(); 467 jedis.del(key); 468 } catch (Exception e) { 469 //释放redis对象 470 e.printStackTrace(); 471 } finally { 472 //返还到连接池 473 jedis.close(); 474 } 475 } 476 477 public static long llen(byte[] key) { 478 479 long len = 0; 480 Jedis jedis = null; 481 try { 482 jedis = jedisPool.getResource(); 483 jedis.llen(key); 484 } catch (Exception e) { 485 //释放redis对象 486 e.printStackTrace(); 487 } finally { 488 //返还到连接池 489 jedis.close(); 490 } 491 return len; 492 } 493 494 }
5.Test 测试类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package redis; 2 3 import java.io.IOException; 4 5 public class Test { 6 public static byte[] redisKey = "key".getBytes(); 7 8 /** 9 * 初始化队列 10 * @throws IOException 11 */ 12 13 static { 14 try { 15 initStart(); 16 } catch (IOException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 } 21 22 private static void initStart() throws IOException { 23 for(int i=0 ; i < 10 ; i++) { 24 Message message = new Message(i,"这是第"+i+"个内容"); 25 RedisUtils.lpush(redisKey, ObjectUtil.object2Bytes(message)); 26 } 27 } 28 29 private static void pop() throws Exception { 30 byte[] bytes = RedisUtils.rpop(redisKey); 31 Message msg = (Message)ObjectUtil.bytes2Object(bytes); 32 if(msg != null ) { 33 System.out.println(msg.getId()+"----"+msg.getContent()); 34 } 35 } 36 public static void main(String[] args) { 37 try { 38 Test.pop(); 39 System.out.println("退出"); 40 } catch (Exception e) { 41 // TODO Auto-generated catch block 42 e.printStackTrace(); 43 } 44 } 45 }
---恢复内容结束---