[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圖示

### 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

> 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)

## 2.3 Hash數據結構
### 2.3.1 Hash圖示
> Redis中的Hashes類型可以看成具有String Key和String Value的map容器

### 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庫中就形成了這樣一條數據:

> 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存儲內容示意圖

### 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中查詢分數最高的同現商品,推薦給該用戶
> 設計思想如下,詳見《代碼》

- 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實戰