[TOC]
# Redis使用及API
## 01/ 客户端连接
### 1、 用redis自带的命令行客户端
~~~
[root@notrue-centos redis]# bin/redis-cli -h notrue-centos -p 6379
redis notrue-centos:6379> ping
PONG
redis notrue-centos:6379>
~~~
### 2、 或者用redis的api客户端连接
> 新建一个maven工程,导入jedis的maven依赖坐标
~~~
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
~~~
> 然后写一个类用来测试服务器跟客户端的连通性:
~~~
public class RedisClientConnectionTest {
public static void main(String[] args) {
// 构造一个redis的客户端对象
Jedis jedis = new Jedis("pinshutang.zicp.net", 6379);
String ping = jedis.ping();
System.out.println(ping);
}
}
~~~
## 2 Redis的数据功能
### 2.1 String类型的数据(常作为缓存使用)
> 1/插入和读取一条string类型的数据
~~~
redis notrue-centos:6379> set sessionid-0001 "zhangsan"
OK
redis notrue-centos:6379> get sessionid-0001
"zhangsan"
~~~
> 2/对string类型数据进行增减(前提是这条数据的value可以看成数字)
~~~
DECR key
INCR key
DECRBY key decrement
INCRBY key increment
~~~
> 3/一次性插入或者获取多条数据
~~~
MGET key1 key2
MSET key1 value1 key2 value2 …..
~~~
> 4/在插入一条string类型数据的同时为它指定一个存活期限
~~~
setex bancao 10 weige
### bancao这条数据就只会存活10秒钟,过期会被redis自动清除
~~~
> 应用:将一个自定义的对象比如product存入redis
> 实现方式一:将对象序列化成byte数组
~~~
/**
* 将对象缓存到redis的string结构数据中
* @throws Exception
*
*/
@Test
public void testObjectCache() throws Exception{
ProductInfo p = new ProductInfo();
p.setName("苏菲");
p.setDescription("angelababy专用");
p.setCatelog("unknow");
p.setPrice(10.8);
//将对象序列化成字节数组
ByteArrayOutputStream ba = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(ba);
//用对象序列化流来将p对象序列化,然后把序列化之后的二进制数据写到ba流中
oos.writeObject(p);
//将ba流转成byte数组
byte[] pBytes = ba.toByteArray();
//将对象序列化之后的byte数组存到redis的string结构数据中
jedis.set("product:01".getBytes(), pBytes);
//根据key从redis中取出对象的byte数据
byte[] pBytesResp = jedis.get("product:01".getBytes());
//将byte数据反序列出对象
ByteArrayInputStream bi = new ByteArrayInputStream(pBytesResp);
ObjectInputStream oi = new ObjectInputStream(bi);
//从对象读取流中读取出p对象
ProductInfo pResp = (ProductInfo) oi.readObject();
System.out.println(pResp);
}
~~~
> 实现方式二:
> 将对象转成json字符串来存取
/**
* 将对象转成json字符串缓存到redis的string结构数据中
*/
@Test
public void testObjectToJsonCache(){
ProductInfo p = new ProductInfo();
p.setName("ABC");
p.setDescription("刘亦菲专用");
p.setCatelog("夜用型");
p.setPrice(10.8);
//利用gson将对象转成json串
Gson gson = new Gson();
String pJson = gson.toJson(p);
//将json串存入redis
jedis.set("prodcut:02", pJson);
//从redis中取出对象的json串
String pJsonResp = jedis.get("prodcut:02");
//将返回的json解析成对象
ProductInfo pResponse = gson.fromJson(pJsonResp, ProductInfo.class);
//显示对象的属性
System.out.println(pResponse);
}
## 2.2 List数据结构
### 2.2.1 List图示
![](https://box.kancloud.cn/d24d21df81027017b44c2c125800bc7f_157x165.png)
### 3.2.2 List功能演示
~~~
#从头部(左边)插入数据
redis>LPUSH key value1 value2 value3
#从尾部(右边)插入数据
redis>RPUSH key value1 value2 value3
#读取list中指定范围的values
redis>LRANGE key start end
redis> lrange task-queue 0 -1 读取整个list
#从头部弹出一个元素
LPOP key
#从尾部弹出一个元素
RPOP key
#从一个list的尾部弹出一个元素插入到另一个list
RPOPLPUSH key1 key2 ## 这是一个原子性操作
~~~
### 2.2.3 List的应用案例demo
> 1 需求描述
> 任务调度系统:
> 生产者不断产生任务,放入task-queue排队
> 消费者不断拿出任务来处理,同时放入一个tmp-queue暂存,如果任务处理成功,则清除tmp-queue,否则,将任务弹回task-queue
![](https://box.kancloud.cn/74748498002520b4c94a4fc483bbd718_444x174.png)
> 2 代码实现
> 1/ 生产者
> ——模拟产生任务
~~~
public class TaskProducer {
// 获取一个redis的客户端连接对象
public static Jedis getRedisConnection(String host, int port) {
Jedis jedis = new Jedis(host, port);
return jedis;
}
public static void main(String[] args) {
Jedis jedis = getRedisConnection("angelababy", 6379);
Random random = new Random();
// 生成任务
while (true) {
try {
// 生成任务的速度有一定的随机性,在1-2秒之间
Thread.sleep(random.nextInt(1000) + 1000);
// 生成一个任务
String taskid = UUID.randomUUID().toString();
// 往任务队列"task-queue"中插入,第一次插入时,"task-queue"还不存在
//但是lpush方法会在redis库中创建一条新的list数据
jedis.lpush("task-queue", taskid);
System.out.println("向任务队列中插入了一个新的任务: " + taskid);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
~~~
> 2/ 消费者
> ——模拟处理任务,并且管理暂存队列
~~~
public class TaskConsumer {
public static void main(String[] args) {
Jedis jedis = new Jedis("angelababy", 6379);
Random random = new Random();
while (true) {
try {
// 从task-queue中取一个任务,同时放入"tmp-queue"
String taskid = jedis.rpoplpush("task-queue", "tmp-queue");
// 模拟处理任务
Thread.sleep(1000);
// 模拟有成功又有失败的情况
int nextInt = random.nextInt(13);
if (nextInt % 7 == 0) { // 模拟失败的情况
// 失败的情况下,需要将任务从"tmp-queue"弹回"task-queue"
jedis.rpoplpush("tmp-queue", "task-queue");
System.out.println("-------任务处理失败: " + taskid);
} else { // 模拟成功的情况
// 成功的情况下,将任务从"tmp-queue"清除
jedis.rpop("tmp-queue");
System.out.println("任务处理成功: " + taskid);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
~~~
> 上述机制是一个简化版,真实版的任务调度系统会更加复杂,如下所示:
> (增加了一个专门用来管理暂存队列的角色,以便就算消费者程序失败退出,那些处理失败的任务依然可以被弹回task-queue)
![](https://box.kancloud.cn/57c691d7bef60c4924f32ad599b106ee_442x184.png)
## 2.3 Hash数据结构
### 2.3.1 Hash图示
> Redis中的Hashes类型可以看成具有String Key和String Value的map容器
![](https://box.kancloud.cn/d490724442dcb1b5dd8955cb2858c761_202x131.png)
### 2.3.2 Hash功能演示
> 1、往redis库中插入一条hash类型的数据
~~~
redis> HSET key field value
~~~
> 举例:
~~~
redis 127.0.0.1:6379> hset user001:zhangsan iphone 6
(integer) 1
redis 127.0.0.1:6379> hset user001:zhangsan xiaomi 7
(integer) 1
redis 127.0.0.1:6379> hset user001:zhangsan meizu 8
(integer) 1
~~~
> 在redis库中就形成了这样一条数据:
![](https://box.kancloud.cn/12fc72620c82722a8dd415ae7d246492_397x195.png)
> 2、从redis库中获取一条hash类型数据的value
> 取出一条hash类型数据中所有field-value对
~~~
redis 127.0.0.1:6379> hgetall user001:zhangsan
1) "iphone"
2) "6"
3) "xiaomi"
4) "7"
5) "meizu"
6) "8"
~~~
> 取出hash数据中所有fields
~~~
redis 127.0.0.1:6379> HKEYS user001:zhangsan
1) "iphone"
2) "xiaomi"
3) "meizu"
~~~
> 取出hash数据中所有的value
~~~
redis 127.0.0.1:6379> hvals user001:zhangsan
1) "6"
2) "7"
3) "8"
~~~
> 取出hash数据中一个指定field的值
~~~
redis 127.0.0.1:6379> hget user001:zhangsan xiaomi
"8"
~~~
> 为hash数据中指定的一个field的值进行增减
~~~
redis 127.0.0.1:6379> HINCRBY user001:zhangsan xiaomi 1
(integer) 8
~~~
> 从hash数据中删除一个字段field及其值
~~~
redis 127.0.0.1:6379> hgetall user001:zhangsan
1) "iphone"
2) "6"
3) "xiaomi"
4) "7"
5) "meizu"
6) "8"
redis 127.0.0.1:6379> HDEL user001:zhangsan iphone
(integer) 1
redis 127.0.0.1:6379> hgetall user001:zhangsan
1) "xiaomi"
2) "7"
3) "meizu"
4) "8"
~~~
## 2.4 Set数据结构功能
> 集合的特点:无序、无重复元素
### 1、 插入一条set数据
~~~
redis 127.0.0.1:6379> sadd frieds:zhangsan bingbing baby fengjie furong ruhua tingting
(integer) 6
redis 127.0.0.1:6379> scard frieds:zhangsan
(integer) 6
redis 127.0.0.1:6379>
~~~
### 2、获取一条set数据的所有members
~~~
redis 127.0.0.1:6379> smembers frieds:zhangsan
1) "fengjie"
2) "baby"
3) "furong"
4) "bingbing"
5) "tingting"
6) "ruhua"
~~~
### 3、判断一个成员是否属于某条指定的set数据
~~~
redis 127.0.0.1:6379> sismember frieds:zhangsan liuyifei #如果不是,则返回0
(integer) 0
redis 127.0.0.1:6379> sismember frieds:zhangsan baby #如果是,则返回1
(integer) 1
~~~
### 4、求两个set数据的差集
> #求差集
~~~
redis 127.0.0.1:6379> sdiff frieds:zhangsan friends:xiaotao
1) "furong"
2) "fengjie"
3) "ruhua"
4) "feifei"
~~~
> #求差集,并将结果存入到另一个set
~~~
redis 127.0.0.1:6379> sdiffstore zhangsan-xiaotao frieds:zhangsan friends:xiaotao
(integer) 4
~~~
> #查看差集结果
~~~
redis 127.0.0.1:6379> smembers zhangsan-xiaotao
1) "furong"
2) "fengjie"
3) "ruhua"
4) "feifei"
~~~
### 5、 求交集,求并集
> #求交集
~~~
redis 127.0.0.1:6379> sinterstore zhangsan:xiaotao frieds:zhangsan friends:xiaotao
(integer) 2
redis 127.0.0.1:6379> smembers zhangsan:xiaotao
1) "bingbing"
2) "baby"
~~~
> #求并集
~~~
redis 127.0.0.1:6379> sunion frieds:zhangsan friends:xiaotao
1) "fengjie"
2) "tangwei"
3) "liuyifei"
4) "bingbing"
5) "ruhua"
6) "feifei"
7) "baby"
8) "songhuiqiao"
9) "furong"
10) "yangmi"
~~~
## 2.5 sortedSet(有序集合)数据结构
### 2.5.1 sortedSet图示
> sortedset中存储的成员都有一个附带的分数值
> 而redis就可以根据分数来对成员进行各种排序(正序、倒序)
> sortedSet存储内容示意图
![](https://box.kancloud.cn/73ca5773a43305c388ceeb5d3f120a7a_377x183.png)
### 2.5.2 SortedSet功能演示
> 1、往redis库中插入一条sortedset数据
~~~
redis 127.0.0.1:6379> zadd nansheng:yanzhi:bang 70 liudehua 90 huangbo 100 weixiaobao 250 yangwei 59 xiaotao
(integer) 5
~~~
> 2、 从sortedset中查询有序结果
> #正序结果
~~~
redis 127.0.0.1:6379> zrange nanshen:yanzhi:bang 0 4
1) "xiaotao"
2) "liudehua"
3) "huangbo"
4) "weixiaobao"
5) "yangwei"
~~~
> #倒序结果
~~~
redis 127.0.0.1:6379> zrevrange nanshen:yanzhi:bang 0 4
1) "yangwei"
2) "weixiaobao"
3) "huangbo"
4) "liudehua"
5) "xiaotao"
~~~
> 3、 查询某个成员的名次
> #在正序榜中的名次
~~~
redis 127.0.0.1:6379> zrank nanshen:yanzhi:bang xiaotao
(integer) 0
~~~
> #在倒序榜中的名次
~~~
redis 127.0.0.1:6379> zrevrank nanshen:yanzhi:bang xiaotao
(integer) 4
~~~
> 4、修改成员的分数
~~~
redis 127.0.0.1:6379> zincrby nanshen:yanzhi:bang 300 xiaotao
"359"
redis 127.0.0.1:6379> zrevrank nanshen:yanzhi:bang xiaotao
(integer) 0
~~~
## 06/ Redis应用案例(1)
> 案例:
> Lol盒子英雄数据排行榜:
> 1、 在redis中需要一个榜单所对应的sortedset数据
> 2、 玩家每选择一个英雄打一场游戏,就对sortedset数据的相应的英雄分数+1
> 3、 Lol盒子上查看榜单时,就调用zrange来看榜单中的排序结果
## 07/ Redis应用案例(2)
> 实现步骤:
> 1、 每来一个用户创建购物车,就对购物车中的每一件商品在redis中插入一条以商品名称为key的sortedset,成员为同时出现在购物车中的其他商品,分数为1
> 2、 每新产生一个购物车,就对车中的商品更新redis中的sortedset,将同时出现的商品的分数增1
> 3、 推荐时,用户放入一件商品到购物车,则从这件商品对应的sortedset中查询分数最高的同现商品,推荐给该用户
> 设计思想如下,详见《代码》
![](https://box.kancloud.cn/e6f9fecd701367736ff0dc0eb30c7fde_555x358.png)
- hadoop
- linux基础
- Linux入门
- Linux进阶
- shell
- Zookeeper
- Zookeeper简介及部署
- Zookeeper使用及API
- Redis
- Redis简介安装部署
- Redis使用及API
- Java高级增强
- Java多线程增强
- Maven简介及搭建
- Hive
- Hive简介及安装
- Hive操作
- HIve常用函数
- Hive数据类型
- Flume
- Flume简介及安装
- flume 拦截器(interceptor)
- azkaban
- azKaban简介及安装
- Sqoop
- Sqoop简介及安装
- HDFS
- HDFS原理
- HDFS操作API
- MAPREDUCE原理
- MAPREDUCE图片资源
- MAPREDUCE加强
- HBASE
- HBASE简介及安装
- HBASE操作及API
- HBASE内部原理
- Storm
- Storm简介及安装
- Storm原理
- kafka
- kafka简介及安装
- kafka常用操作及API
- kafka原理
- kafka配置详解
- Scala
- Scala简介及安装
- Scala基础语法
- Scala实战