redis 學習筆記

一、redis學習

 

01/ nosql介紹

 

NoSQL:一類新出現的數據庫(not only sql),它的特點:

1、 不支持SQL語法

2、 存儲結構跟傳統關係型數據庫中的那種關係表完全不同,nosql中存儲的數據都是KV形式

3、 NoSQL的世界中沒有一種通用的語言,每種nosql數據庫都有自己的api和語法,以及擅長的業務場景

4、 NoSQL中的產品種類相當多:

a) Mongodb  文檔型nosql數據庫,擅長做CMS系統(內容管理系統)

b) Redis 內存數據庫,數據結構服務器,號稱瑞士軍刀(精巧),只要你有足夠的想象力,它可以還給你無限驚喜

c) Hbase  hadoop生態系統中原生的一種nosql數據庫,重量級的分佈式nosql數據庫,用於海量數據的場景

d) Cassandra  hadoop生態系統中原生的一種分佈式nosql數據庫,後起之秀

 

NoSQLSQL數據庫的比較:

1、適用場景不同:sql數據庫適合用於關係特別複雜的數據查詢場景,nosql反之

2“事務”特性的支持:sql對事務的支持非常完善,而nosql基本不支持事務

3、兩者在不斷地取長補短,呈現融合趨勢

 

 

02/ redis介紹

2.1 簡述

Redis是一個高性能的kv緩存和內存數據庫(存的不像mysql那樣的表)

Redis的存儲結構就是key-value,形式如下:

 

注: redis中的value內部可以支持各種數據結構類型,比如可以存入一個普通的string,還可以存listsethashmapsortedSet(有序的set

 

 

2.2 redis應用場景

A、用來做緩存(ehcache/memcached)——redis的所有數據是放在內存中的(內存數據庫)

B、可以在某些特定應用場景下替代傳統數據庫——比如社交類的應用

C、在一些大型系統中,巧妙地實現一些特定的功能:session共享、購物車

只要你有豐富的想象力,redis可以用在可以給你無限的驚喜…….

 

 

2.3 redis的特性

1redis數據訪問速度快(數據在內存中)

2redis有數據持久化機制(持久化機制有兩種:1、定期將內存數據dump到磁盤;2aof(append only file)持久化機制——用記日誌的方式記錄每一條數據更新操作,一旦出現災難事件,可以通過日誌重放來恢復整個數據庫)

3redis支持集羣模式(容量可以線性擴展)

4redis相比其他緩存工具(ehcach/memcached),有一個鮮明的優勢:支持豐富的數據結構

 

 

03/ 安裝redis

3.1 獲取源碼包

1、先去官網(http://redis.io/download )下載一個源碼工程(redis官網版本只支持linux/微軟開源事業部維護了一個windows版本)

2、把安裝包上傳到服務器,解壓縮

 

3.2 編譯源碼

1、切換到解壓出來的源碼工程目錄中   

cd redis-2.6.16 

2、用make命令來對redisc語言源碼工程進行編譯

3、編譯完成之後,用make  install命令進行安裝

[root@notrue-centos redis-2.6.16]# make  PREFIX=/usr/local/redis  install

安裝成功的顯示:

 

 

3.3 啓動redis服務

1進入redisbin目錄

 

 

2、準備配置文件

Redis服務在啓動的時候可以指定配置文件,那,我們可以從redis的源碼目錄中拷貝一份配置文件模板到redis的安裝目錄,修改後使用

[root@notrue-centos redis-2.6.16]# cp /root/redis-2.6.16/redis.conf /usr/local/redis/

 

3啓動redis服務

並指定使用的配置文件

 

 

4啓動成功的顯示

 

 

5、啓動爲後臺服務

上述啓動方法,會讓redis服務進程運行在console前臺,最好應該放到後臺運行,可將啓動命令改爲如下方式:

1/ 方式一

[root@notrue-centos redis]# nohup bin/redis-server ./redis.conf 1>/dev/null 2>&1 &

Nohup:控制檯關閉或閒置超時,也不退出

1>/dev/null : 把程序的“1”——標準輸出,重定向到文件/dev/null

2>&1      : 把程序的“2”——錯誤輸出,重定向到“1”所去的文件

&         :   把程序放到後臺運行             

 

 

2/ 方式二

修改配置文件,

vi  redis.conf

修改其中一個配置

 

保存文件後再用普通命令啓動,也可以啓動爲後臺模式

[root@notrue-centos redis]# bin/redis-server  ./redis.conf

 

04/ 客戶端連接

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、 或者用redisapi客戶端連接

新建一個maven工程,導入jedismaven依賴座標

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

}

}

 

 

 

05/ Redis的數據功能

5.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數組

/**

 * 將對象緩存到redisstring結構數據中

 * @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數組存到redisstring結構數據中

jedis.set("product:01".getBytes(), pBytes);

//根據keyredis中取出對象的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字符串緩存到redisstring結構數據中

 */

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

}

 

 

 

 

 

5.2 List數據結構

5.2.1 List圖示

 

 

 

5.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     ## 這是一個原子性操作

 

 

5.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

 

5.3 Hash數據結構

5.3.1 Hash圖示

Redis中的Hashes類型可以看成具有String KeyString Valuemap容器


 

5.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"

 

 

5.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"

 

 

 

 

 

5.5 sortedSet(有序集合)數據結構

5.5.1 sortedSet圖示

sortedset中存儲的成員都有一個附帶的分數值

redis就可以根據分數來對成員進行各種排序(正序、倒序)

 

1、 sortedSet存儲內容示意圖:

 

 

5.5.2 SortedSet功能演示

1redis庫中插入一條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來看榜單中的排序結果

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章