1. 程式人生 > >Redis快速入門視頻課程——隨堂筆記(一)

Redis快速入門視頻課程——隨堂筆記(一)

mongodb 雨後春筍 和數 auth 鍵值對 密碼 ref 種類型 .gz

視頻課程鏈接:http://edu.51cto.com/course/14463.html

Redis內存數據庫,主講:湯小洋

一、Redis簡介

1. 關於NoSQL

? NoSQL的全稱是Not only SQL,在過去的幾年中,NoSQL數據庫一度成為高並發、海量數據存儲解決方案的代名詞,與之相應的產品也呈現出雨後春筍般的生機。然而在眾多產品中能夠脫穎而出的卻屈指可數,如Redis、MongoDB、BerkeleyDB和memcached等內存數據庫。由於每種產品所擁有的特征不同,因此它們的應用場景也存在著一定的差異,下面僅給出簡單的說明:
? 1). BerkeleyDB是一種極為流行的開源嵌入式數據庫,在更多情況下可用於存儲引擎,比如BerkeleyDB在被Oracle收購之前曾作為MySQL的存儲引擎,由此可以預見,該產品擁有極好的並發伸縮性,支持事務及嵌套事務,海量數據存儲等重要特征,在用於存儲實時數據方面具有極高的可用價值。然而需要指出的是,該產品的Licence為GPL,這就意味著它並不是在所有情況下都是免費使用的。

? 2). 對MongoDB的定義為Oriented-Document數據庫服務器,和BerkeleyDB不同的是該數據庫可以像其他關系型數據庫服務器那樣獨立的運行並提供相關的數據服務。從該產品的官方文檔中我們可以獲悉,MongoDB主要適用於高並發的論壇或博客網站,這些網站具有的主要特征是並發訪問量高、多讀少寫、數據量大、邏輯關系簡單,以及文檔數據作為主要數據源等。和BerkeleyDB一樣,該產品的License同為GPL。
? 3). Redis,典型的NoSQL數據庫服務器,和BerkeleyDB相比,它可以作為服務程序獨立運行於自己的服務器主機。在很多時候,人們只是將Redis視為Key/Value數據庫服務器,然而事實並非如此,在目前的版本中,Redis除了Key/Value之外還支持List、Set、Hash和Ordered Set等數據結構,因此它的用途也更為寬泛。和以上兩種產品不同的是,Redis的License是Apache License,就目前而言,它是完全免費。
? 4). memcached,數據緩存服務器。它們之間的最大區別,memcached只是提供了數據緩存服務,一旦服務器宕機,之前在內存中緩存的數據也將全部消失,因此可以看出memcached沒有提供任何形式的數據持久化功能,而Redis則提供了這樣的功能。再有就是Redis提供了更為豐富的數據存儲結構,如Hash和Set。至於它們的相同點,主要有兩個,一是完全免費,再有就是它們的提供的命令形式極為接近。

2. Redis的優勢

? 1). 和其他NoSQL產品相比,Redis的易用性極高,因此對於那些有類似產品使用經驗的開發者來說,一兩天,甚至是幾個小時之後就可以利用Redis來搭建自己的平臺了。

? 2). 在解決了很多通用性問題的同時,也為一些個性化問題提供了相關的解決方案,如索引引擎、統計排名、消息隊列服務等。

3. 和關系型數據庫的比較

? 在目前版本的Redis中,提供了對五種不同數據類型的支持,其中只有String類型可以被視為Key-Value結構,而其他的數據類型均有適用於各自特征的應用場景。
? 相比於關系型數據庫,由於其存儲結構相對簡單,因此Redis並不能對復雜的邏輯關系提供很好的支持,然而在適用於Redis的場景中,我們卻可以由此而獲得效率上的顯著提升。即便如此,Redis還是為我們提供了一些數據庫應該具有的基礎概念,如:在同一連接中可以選擇打開不同的數據庫,然而不同的是,Redis中的數據庫是通過數字來進行命名的,缺省情況下打開的數據庫為0。如果程序在運行過程中打算切換數據庫,可以使用Redis的select命令來打開其他數據庫,如select 1,如果此後還想再切換回缺省數據庫,只需執行select 0即可。
在數據存儲方面,Redis遵循了現有NoSQL數據庫的主流思想,即Key作為數據檢索的唯一標識,我們可以將其簡單的理解為關系型數據庫中索引的鍵,而Value則作為數據存儲的主要對象,其中每一個Value都有一個Key與之關聯,這就好比索引中物理數據在數據表中存儲的位置。在Redis中,Value將被視為二進制字節流用於存儲任何格式的數據,如Json、XML和序列化對象的字節流等,因此我們也可以將其想象為關系型數據庫中的BLOB類型字段。由此可見,在進行數據查詢時,我們只能基於Key作為我們查詢的條件,當然我們也可以應用Redis中提供的一些技巧將Value作為其他數據的Key。

4. 如何持久化內存數據

? 缺省情況下,Redis會參照當前數據庫中數據被修改的數量,在達到一定的閾值後會將數據庫的快照存儲到磁盤上,這一點我們可以通過配置文件來設定該閾值。通常情況下,我們也可以將Redis設定為定時保存。如當有1000個以上的鍵數據被修改時,Redis將每隔60秒進行一次數據持久化操作。缺省設置為,如果有9個或9個以下數據修改時,Redis將每15分鐘持久化一次。
? 從上面提到的方案中可以看出,如果采用該方式,Redis的運行效率將會是非常高效的,每當有新的數據修改發生時,僅僅是內存中的緩存數據發生改變,而這樣的改變並不會被立即持久化到磁盤上,從而在絕大多數的修改操作中避免了磁盤IO的發生。然而事情往往是存在其兩面性的,在該方法中我們確實得到了效率上的提升,但是卻失去了數據可靠性。如果在內存快照被持久化到磁盤之前,Redis所在的服務器出現宕機,那麽這些未寫入到磁盤的已修改數據都將丟失。為了保證數據的高可靠性,Redis還提供了另外一種數據持久化機制--Append模式。如果Redis服務器被配置為該方式,那麽每當有數據修改發生時,都會被立即持久化到磁盤。

二、安裝Redis

1. 安裝

? 步驟:

  1. 解壓redis-3.2.8.tar.gz

    cd ~/software
    tar -zxf redis-3.2.8.tar.gz
  2. 編譯

    cd redis-3.2.8
    make
  3. 安裝

    mkdir ~/software/redis-bin
    make install PREFIX=~/software/redis-bin/   #PREFIX選項用來指定安裝的位置
  4. 啟動redis

    cd ~/software/redis-bin/bin/
    ./redis-server #使用默認配置文件啟動,默認配置文件所在目錄redis-3.2.8/redis.conf
    或
    cp ~/software/redis-3.2.8/redis.conf myredis.conf  #復制默認配置文件到當前目錄,並改名
    ./redis-server myredis.conf #使用指定的配置文件啟動

    ? 補充:可以將~/software/redis-bin/bin/添加到PATH變量中,便於執行命令

    vi ~/.bashrc
    export PATH=$PATH:/Users/wangbo/software/redis-bin/bin
    source   ~/.bashrc
  5. 連接redis

    ./redis-cli  #默認連接本機的6379端口(redis默認使用的端口號)
    或
    ./redis-cli -h IP地址 -p 端口號  #連接指定主機、指定端口的redis,如./redis-cli -h localhost -p 6379

    ? 測試

    127.0.0.1:6379> set name tom
    127.0.0.1:6379> get name

2. 關閉

? 兩種方式

  • 方式1:在服務器窗口中按 Ctrl+C
  • 方式2:在客戶端連接後輸入 shutdown 或 直接輸入 redis-cli shutdown

? 查看redis進程

ps aux | grep redis #查看redis的進程信息
或
lsof -i:6379 #查看6379端口的進程信息

3. 配置

? 編輯配置文件:

$ vi myredis.conf
    daemonize yes           #配置為守護進程,後臺啟動

    port 6379               #修改監聽端口

    #讓redis支持遠程訪問,默認只允許本地訪問
    #bind    127.0.0.1      #註釋掉該行,允許所有主機訪問redis
    protected-mode no       #關閉保護模式

    requirepass itany       #配置redis密碼,使用時需要輸入:auth itany進行認證,認證後才能操作redis

三、Redis數據類型

1. 簡介

? Redis數據就是以key-value形式來存儲的,key只能是字符串類型,value可以是以下五種類型:String、List、Set、Sorted-Sets、Hash

2. String類型

2.1 簡介

? 字符串類型是Redis中最為基礎的數據存儲類型,它在Redis中是二進制安全的,這便意味著該類型可以接受任何格式的數據,如JPEG圖像數據或Json對象描述信息等。在Redis中字符串類型的Value最多可以容納的數據長度是512M。

2.2 操作

  • set/get/append/strlen

    $ redis-cli 
    127.0.0.1:6379> select 0                  #切換到第1個數據庫,默認共有16個數據庫,索引從0開始
    OK
    127.0.0.1:6379> keys *                        #顯示所有的鍵key
    (empty list or set)
    127.0.0.1:6379> set name tom              #設置鍵
    OK
    127.0.0.1:6379> get name                  #獲取鍵對應的值
    "tom"
    127.0.0.1:6379> exists mykey                  #判斷該鍵是否存在,存在返回1,不存在返回0
    (integer) 0
    127.0.0.1:6379> append mykey "hello"          #如果該鍵不存在,則創建,返回當前value的長度
    (integer) 5
    127.0.0.1:6379> append mykey " world"         #如果該鍵已經存在,則追加,返回追加後value的長度
    (integer) 11
    127.0.0.1:6379> get mykey                   #獲取mykey的值
    "hello world"
    127.0.0.1:6379> strlen mykey                  #獲取mykey的長度
    (integer) 11
    #EX和PX表示失效時間,單位為秒和毫秒,兩者不能同時使用;NX表示數據庫中不存在時才能設置,XX表示存在時才能設置
    127.0.0.1:6379> set mykey "this is test"  EX 5 NX  
    OK
    127.0.0.1:6379> get mykey
    "this is test"

    ? 註:命令不區分大小寫,但key和value區分大小寫

  • incr/decr/incrby/decrby

    127.0.0.1:6379> flushdb                       #清空數據庫
    OK
    127.0.0.1:6379> set mykey 20
    OK
    127.0.0.1:6379> incr mykey                #遞增1
    (integer) 21
    127.0.0.1:6379> decr mykey                #遞減1
    (integer) 20
    127.0.0.1:6379> del mykey                     #刪除該鍵
    (integer) 1
    127.0.0.1:6379> decr mykey
    (integer) -1
    127.0.0.1:6379> del mykey
    (integer) 1
    127.0.0.1:6379> INCR mykey
    (integer) 1
    127.0.0.1:6379> set mykey ‘hello‘         #將該鍵的Value設置為不能轉換為整型的普通字符串
    OK
    127.0.0.1:6379> incr mykey                #在該鍵上再次執行遞增操作時,Redis將報告錯誤信息
    (error) ERR value is not an integer or out of range
    127.0.0.1:6379> set mykey 10
    OK
    127.0.0.1:6379> incrby mykey 5                #遞增5,即步長
    (integer) 15
    127.0.0.1:6379> decrby mykey 10               #遞減10
    (integer) 5
  • getset/setex/setnx

    #   getset    獲取的同時並設置新的值
    127.0.0.1:6379> incr mycount                  #將計數器的值原子性的遞增1
    (integer) 1
    127.0.0.1:6379> getset mycount 666            #在獲取計數器原有值的同時,並將其設置為新值
    "1"
    127.0.0.1:6379> get mycount
    "666"
    
    # setex   設置過期時間
    127.0.0.1:6379> setex mykey 10 "hello"        #設置指定Key的過期時間為10秒,等同於set mykey hello ex 10
    OK
    127.0.0.1:6379> ttl mykey                 #查看指定Key的過期時間(秒數)
    (integer) 8
    
    # setnx   當key不存在時才能設置  
    127.0.0.1:6379> del mykey
    (integer) 0
    127.0.0.1:6379> setnx mykey "aaa"             #key不存在,可以設置,等同於set mykey aaa nx
    (integer) 1
    127.0.0.1:6379> setnx mykey "bbb"         #key存在,不能設置
    (integer) 0
    127.0.0.1:6379> get mykey
    "aaa"
  • setrange/getrange 設置/獲取指定索引位置的字符

    127.0.0.1:6379> set mykey "hello world"
    OK
    127.0.0.1:6379> get mykey
    "hello world"
    127.0.0.1:6379> setrange mykey 6 dd           #從索引為6的位置開始替換(索引從0開始)
    (integer) 11
    127.0.0.1:6379> get mykey
    "hello ddrld"
    127.0.0.1:6379> setrange mykey 20 dd        #超過的長度使用0代替
    (integer) 22
    127.0.0.1:6379> get mykey
    "hello ddrld\x00\x00\x00\x00\x00\x00\x00\x00\x00dd"
    127.0.0.1:6379> getrange mykey 3 12           #獲取索引為[3,12]之間的內容
    "lo ddrld\x00\x00"

    setbit/getbit 設置/獲取指定位的BIT值,應用場景:考勤打卡

    127.0.0.1:6379> del mykey
    (integer) 1
    127.0.0.1:6379> setbit mykey 7 1              #設置從0開始計算的第七位BIT值為1,返回原有BIT值0
    (integer) 0
    127.0.0.1:6379> get mykey                 #獲取設置的結果,二進制的0000 0001的十六進制值為0x01
    "\x01"
    127.0.0.1:6379> setbit mykey 6 1              #設置從0開始計算的第六位BIT值為1,返回原有BIT值0
    (integer) 0
    127.0.0.1:6379> get mykey                 #獲取設置的結果,二進制的0000 0011的十六進制值為0x03
    "\x03"
    127.0.0.1:6379> getbit mykey 6            #返回了指定Offset的BIT值
    (integer) 1
    127.0.0.1:6379> getbit mykey 10               #如果offset已經超出了value的長度,則返回0
    (integer) 0
  • mset/mget/msetnx

    127.0.0.1:6379> mset key1 "hello" key2 "world"    #批量設置了key1和key2兩個鍵。
    OK
    127.0.0.1:6379> mget key1 key2                    #批量獲取了key1和key2兩個鍵的值。
    1) "hello"
    2) "world"
    #批量設置了key3和key4兩個鍵,因為之前他們並不存在,所以該命令執行成功並返回1
    127.0.0.1:6379> msetnx key3 "itany" key4 "liu" 
    (integer) 1
    127.0.0.1:6379> mget key3 key4                   
    1) "itany"
    2) "liu"
    #批量設置了key3和key5兩個鍵,但是key3已經存在,所以該命令執行失敗並返回0
    127.0.0.1:6379> msetnx key3 "hello" key5 "world" 
    (integer) 0
    #批量獲取key3和key5,由於key5沒有設置成功,所以返回nil
    127.0.0.1:6379> mget key3 key5                   
    1) "itany"
    2) (nil)

3. List類型

3.1 概述

? 在Redis中,List類型是按照插入順序排序的字符串鏈表。和數據結構中的普通鏈表一樣,我們可以在其頭部(left)和尾部(right)添加新的元素。在插入時,如果該鍵並不存在,Redis將為該鍵創建一個新的鏈表。與此相反,如果鏈表中所有的元素均被移除,那麽該鍵也將會被從數據庫中刪除。List中可以包含的最大元素數量是4294967295。
? 從元素插入和刪除的效率視角來看,如果我們是在鏈表的兩頭插入或刪除元素,這將會是非常高效的操作,即使鏈表中已經存儲了百萬條記錄,該操作也可以在常量時間內完成。然而需要說明的是,如果元素插入或刪除操作是作用於鏈表中間,那將會是非常低效的。

3.2 操作

  • lpush/lpushx/lrange

    127.0.0.1:6379> flushdb
    OK
    #創建鍵mykey及與其關聯的List,然後將參數中的values從左到右依次插入
    127.0.0.1:6379> lpush mykey a b c d
    (integer) 4
    #獲取從位置0開始到位置2結束的3個元素
    127.0.0.1:6379> lrange mykey 0 2
    1) "d"
    2) "c"
    3) "b"
    #獲取鏈表中的全部元素,其中0表示第一個元素,-1表示最後一個元素
    127.0.0.1:6379> lrange mykey 0 -1
    1) "d"
    2) "c"
    3) "b"
    4) "a"
    #獲取從倒數第3個到倒數第2個的元素
    127.0.0.1:6379> lrange mykey -3 -2
    1) "c"
    2) "b"
    #lpushx表示鍵存在時才能插入,mykey2鍵此時並不存在,因此該命令將不會進行任何操作,其返回值為0
    127.0.0.1:6379> lpushx mykey2 e       
    (integer) 0
    #可以看到mykey2沒有關聯任何List Value
    127.0.0.1:6379> lrange mykey2 0 -1
    (empty list or set)
    #mykey鍵此時已經存在,所以該命令插入成功,並返回鏈表中當前元素的數量
    127.0.0.1:6379> lpushx mykey e
    (integer) 5
    #獲取該鍵的List中的第一個元素
    127.0.0.1:6379> lrange mykey 0 0
    1) "e"
  • lpop/llen

    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> lpush mykey a b c d
    (integer) 4
    #取出鏈表頭部的元素,該元素在鏈表中就已經不存在了
    127.0.0.1:6379> lpop mykey
    "d"
    127.0.0.1:6379> lpop mykey
    "c"
    #在執行lpop命令兩次後,鏈表頭部的兩個元素已經被彈出,此時鏈表中元素的數量是2
    127.0.0.1:6379> llen mykey
    (integer) 2
  • lrem/lindex/lset/ltrim

    127.0.0.1:6379> flushdb
    OK
    #準備測試數據
    127.0.0.1:6379> lpush mykey a b c d a c
    (integer) 6
    #從頭部(left)向尾部(right)操作鏈表,刪除2個值等於a的元素,返回值為實際刪除的數量
    127.0.0.1:6379> lrem mykey 2 a
    (integer) 2
    #查看刪除後鏈表中的全部元素
    127.0.0.1:6379> lrange mykey 0 -1
    1) "c"
    2) "d"
    3) "c"
    4) "b"
    #獲取索引值為1(頭部的第二個元素)的元素值
    127.0.0.1:6379> lindex mykey 1
    "d"
    #將索引值為1(頭部的第二個元素)的元素值設置為新值e
    127.0.0.1:6379> lset mykey 1 e
    OK
    #查看是否設置成功
    127.0.0.1:6379> lindex mykey 1
    "e"
    #索引值6超過了鏈表中元素的數量,該命令返回nil
    127.0.0.1:6379> lindex mykey 6
    (nil)
    #設置的索引值6超過了鏈表中元素的數量,設置失敗,該命令返回錯誤信息。
    127.0.0.1:6379> lset mykey 6 h
    (error) ERR index out of range
    #僅保留索引值0到2之間的3個元素,註意第0個和第2個元素均被保留。
    127.0.0.1:6379> ltrim mykey 0 2
    OK
    #查看trim後的結果
    127.0.0.1:6379> lrange mykey 0 -1
    1) "c"
    2) "e"
    3) "c"
  • linsert

    127.0.0.1:6379> del mykey
    (integer) 1
    #準備測試數據
    127.0.0.1:6379> lpush mykey a b c d e
    (integer) 5
    #在a的前面插入新元素a1
    127.0.0.1:6379> linsert mykey before a a1
    (integer) 6
    #查看是否插入成功,從結果看已經插入
    127.0.0.1:6379> lrange mykey 0 -1
    1) "e"
    2) "d"
    3) "c"
    4) "b"
    5) "a1"
    6) "a"
    #在e的後面插入新元素e2,從返回結果看已經插入成功
    127.0.0.1:6379> linsert mykey after e e2
    (integer) 7
    #再次查看是否插入成功
    127.0.0.1:6379> lrange mykey 0 -1
    1) "e"
    2) "e2"
    3) "d"
    4) "c"
    5) "b"
    6) "a1"
    7) "a"
    #在不存在的元素之前或之後插入新元素,該命令操作失敗,並返回-1
    127.0.0.1:6379> linsert mykey after k a
    (integer) -1
    #為不存在的Key插入新元素,該命令操作失敗,返回0
    127.0.0.1:6379> linsert mykey1 after a a2
    (integer) 0
  • rpush/rpushx/rpop/rpoplpush

    127.0.0.1:6379> del mykey
    (integer) 1
    #從鏈表的尾部插入參數中給出的values,插入順序是從左到右依次插入
    127.0.0.1:6379> rpush mykey a b c d
    (integer) 4
    #查看鏈表中的元素,註意元素的順序
    127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    #該鍵已經存在並且包含4個元素,rpushx命令將執行成功,並將元素e插入到鏈表的尾部。
    127.0.0.1:6379> rpushx mykey e
    (integer) 5
    #由於mykey2鍵並不存在,因此該命令不會插入數據,其返回值為0。
    127.0.0.1:6379> rpushx mykey2 e
    (integer) 0
    #查看鏈表中所有的元素
    127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    5) "e"
    #從尾部(right)彈出元素,即取出元素
    127.0.0.1:6379> rpop mykey
    "e"
    #查看鏈表中所有的元素
    127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    #創建mykey2
    127.0.0.1:6379> lpush mykey2 m n 
    (integer) 2
    #將mykey的尾部元素彈出,然後插入到mykey2的頭部(原子性的完成這兩步操作)
    127.0.0.1:6379> rpoplpush mykey mykey2
    "d"
    #通過lrange命令查看mykey在彈出尾部元素後的結果
    127.0.0.1:6379> lrange mykey 0 -1
    1) "a"
    2) "b"
    3) "c"
    #通過lrange命令查看mykey2在插入元素後的結果
    127.0.0.1:6379> lrange mykey2 0 -1
    1) "d"
    2) "n"
    3) "m"
    127.0.0.1:6379> 
    #將source和destination設為同一鍵,將mykey中的尾部元素移到其頭部
    127.0.0.1:6379> rpoplpush mykey mykey
    "c"
    #查看結果
    127.0.0.1:6379> lrange mykey 0 -1
    1) "c"
    2) "a"
    3) "b"

4. Set類型

4.1 概述

? 在Redis中,我們可以將Set類型看作為沒有排序的字符集合,也可以在該類型的數據值上執行添加、刪除或判斷某一元素是否存在等操作。Set可包含的最大元素數量是4294967295。
? 和List類型不同的是,Set集合中不允許出現重復的元素,這一點和Java中的set容器是完全相同的。換句話說,如果多次添加相同元素,Set中將僅保留該元素的一份拷貝。和List類型相比,Set類型在功能上還存在著一個非常重要的特性,即在服務器端完成多個Sets之間的聚合計算操作,如unions並、intersections交和differences差。由於這些操作均在服務端完成,因此效率極高,而且也節省了大量的網絡IO開銷。

4.2 操作

  • sadd/smembers/sismember/scard

    #由於該鍵myset之前並不存在,因此參數中的三個成員都被正常插入
    127.0.0.1:6379> sadd myset a b c
    (integer) 3
    #查看集合中的元素,從結果可以,輸出的順序和插入順序無關(無序的)
    127.0.0.1:6379> smembers myset
    1) "a"
    2) "c"
    3) "b"
    #由於參數中的a在myset中已經存在,因此本次操作僅僅插入了d和e兩個新成員(不允許重復)
    127.0.0.1:6379> sadd myset a d e
    (integer) 2
    #查看插入的結果
    127.0.0.1:6379> smembers myset
    1) "a"
    2) "c"
    3) "d"
    4) "b"
    5) "e"
    #判斷a是否已經存在,返回值為1表示存在
    127.0.0.1:6379> sismember myset a
    (integer) 1
    #判斷f是否已經存在,返回值為0表示不存在
    127.0.0.1:6379> sismember myset f
    (integer) 0
    #獲取集合中元素的數量
    127.0.0.1:6379> scard myset
    (integer) 5
  • srandmember/spop/srem/smove

    127.0.0.1:6379> del myset
    (integer) 1
    #準備測試數據
    127.0.0.1:6379> sadd myset a b c d
    (integer) 4
    #查看集合中的元素
    127.0.0.1:6379> smembers myset
    1) "c"
    2) "d"
    3) "a"
    4) "b"
    #隨機返回一個成員,成員還在集合中
    127.0.0.1:6379> srandmember myset
    "c"
    #取出一個成員,成員會從集合中刪除
    127.0.0.1:6379> spop myset
    "b"
    #查看移出後Set的成員信息
    127.0.0.1:6379> smembers myset
    1) "c"
    2) "d"
    3) "a"
    #從Set中移出a、d和f三個成員,其中f並不存在,因此只有a和d兩個成員被移出,返回為2
    127.0.0.1:6379> srem myset a d f
    (integer) 2
    #查看移出後的輸出結果
    127.0.0.1:6379> smembers myset
    1) "c"
    
    127.0.0.1:6379> del myset
    (integer) 1
    #為後面的smove命令準備數據
    127.0.0.1:6379> sadd myset a b
    (integer) 2
    127.0.0.1:6379> sadd myset2 c d
    (integer) 2
    #將a從myset移到myset2,從結果可以看出移動成功
    127.0.0.1:6379> smove myset myset2 a
    (integer) 1
    #再次將a從myset移到myset2,由於此時a已經不是myset的成員了,因此移動失敗並返回0。
    127.0.0.1:6379> smove myset myset2 a
    (integer) 0
    #分別查看myset和myset2的成員,確認移動是否真的成功。
    127.0.0.1:6379> smembers myset
    1) "b"
    127.0.0.1:6379> smembers myset2
    1) "c"
    2) "d"
    3) "a"
  • sdiff/sdiffstore/sinter/sinterstore/sunion/sunionstore

    127.0.0.1:6379> flushdb
    OK
    #準備測試數據
    127.0.0.1:6379> sadd myset a b c d
    (integer) 4
    127.0.0.1:6379> sadd myset2 c
    (integer) 1
    127.0.0.1:6379> sadd myset3 a c e
    (integer) 3
    #獲取多個集合之間的不同成員,要註意匹配的規則
    #先將myset和myset2進行比較,a、b和d三個成員是兩者之間的差異成員,然後再用這個結果繼續和myset3進行差異比較,b和d是myset3不存在的成員
    127.0.0.1:6379> sdiff myset myset2 myset3
    1) "d"
    2) "b"
    127.0.0.1:6379> sdiff myset3 myset2 myset
    1) "e"
    #將3個集合的差異成員存儲到與diffkey關聯的Set中,並返回插入的成員數量
    127.0.0.1:6379> sdiffstore diffkey myset myset2 myset3
    (integer) 2
    #查看一下sdiffstore的操作結果
    127.0.0.1:6379> smembers diffkey
    1) "d"
    2) "b"
    #獲取多個集合之間的交集,這三個Set的成員交集只有c
    127.0.0.1:6379> sinter myset myset2 myset3
    1) "c"
    #將3個集合中的交集成員存儲到與interkey關聯的Set中,並返回交集成員的數量
    127.0.0.1:6379> sinterstore interkey myset myset2 myset3
    (integer) 1
    #查看一下sinterstore的操作結果
    127.0.0.1:6379> smembers interkey
    1) "c"
    #獲取多個集合之間的並集
    127.0.0.1:6379> sunion myset myset2 myset3
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "a"
    #將3個集合中成員的並集存儲到unionkey關聯的set中,並返回並集成員的數量
    127.0.0.1:6379> sunionstore unionkey myset myset2 myset3
    (integer) 5
    #查看一下sunionstore的操作結果
    127.0.0.1:6379> smembers unionkey
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "a"

4.3 應用範圍

  1. 可以使用Redis的Set數據類型跟蹤一些唯一性數據,比如訪問某一博客的唯一IP地址信息。對於此場景,我們僅需在每次訪問該博客時將訪問者的IP存入Redis中,Set數據類型會自動保證IP地址的唯一性。
  2. 充分利用Set類型的服務端聚合操作方便、高效的特性,可以用於維護數據對象之間的關聯關系。比如所有購買某一電子設備的客戶ID被存儲在一個指定的Set中,而購買另外一種電子產品的客戶ID被存儲在另外一個Set中,如果此時我們想獲取有哪些客戶同時購買了這兩種商品時,Set的intersections命令就可以充分發揮它的方便和效率的優勢了。

5. Sorted-Sets類型

5.1 概述

? Sorted-Sets和Sets類型極為相似,也稱為Zset,它們都是字符串的集合,都不允許重復的成員出現在一個Set中。它們之間的主要差別是Sorted-Sets中的每一個成員都會有一個分數(score)與之關聯,Redis正是通過分數來為集合中的成員進行從小到大的排序(默認)。然而需要額外指出的是,盡管Sorted-Sets中的成員必須是唯一的,但是分數(score)卻是可以重復的。
? 在Sorted-Set中添加、刪除或更新一個成員都是非常快速的操作。由於Sorted-Sets中的成員在集合中的位置是有序的,因此,即便是訪問位於集合中部的成員也仍然是非常高效的。事實上,Redis所具有的這一特征在很多其它類型的數據庫中是很難實現的,換句話說,在該點上要想達到和Redis同樣的高效,在其它數據庫中進行建模是非常困難的。

5.2 操作

  • zadd/zrange/zcard/zrank/zcount/zrem/zscore/zincrby

    #添加一個分數為1的成員
    127.0.0.1:6379> zadd myzset 1 "one"
    (integer) 1
    #添加兩個分數分別是2和3的兩個成員
    127.0.0.1:6379> zadd myzset 2 "two" 3 "three"
    (integer) 2
    #通過索引獲取元素,0表示第一個成員,-1表示最後一個成員。WITHSCORES選項表示返回的結果中包含每個成員及其分數,否則只返回成員
    127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    #獲取myzset鍵中成員的數量  
    127.0.0.1:6379> zcard myzset
    (integer) 3
    #獲取成員one在集合中的索引,0表示第一個位置
    127.0.0.1:6379> zrank myzset one
    (integer) 0
    #成員four並不存在,因此返回nil
    127.0.0.1:6379> zrank myzset four
    (nil)
    #獲取符合指定條件的成員數量,分數滿足表達式1 <= score <= 2的成員的數量
    127.0.0.1:6379> zcount myzset 1 2
    (integer) 2
    #刪除成員one和two,返回實際刪除成員的數量
    127.0.0.1:6379> zrem myzset one two
    (integer) 2
    #查看是否刪除成功
    127.0.0.1:6379> zcard myzset
    (integer) 1
    #獲取成員three的分數。返回值是字符串形式
    127.0.0.1:6379> zscore myzset three
    "3"
    #由於成員two已經被刪除,所以該命令返回nil
    127.0.0.1:6379> zscore myzset two
    (nil)
    #將成員three的分數增加2,並返回該成員更新後的分數
    127.0.0.1:6379> zincrby myzset 2 three
    "5"
    #將成員three的分數增加-1,並返回該成員更新後的分數
    127.0.0.1:6379> zincrby myzset -1 three
    "4"
    #查看在更新了成員的分數後是否正確
    127.0.0.1:6379> zrange myzset 0 -1 withscores
    1) "three"
    2) "4"
  • zrangebyscore/zremrangebyscore/zremrangebyrank

    127.0.0.1:6379> del myzset
    (integer) 1
    127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
    (integer) 4
    #通過分數獲取元素,獲取分數滿足表達式1 <= score <= 2的成員
    127.0.0.1:6379> zrangebyscore myzset 1 2
    1) "one"
    2) "two"
    #-inf表示第一個成員,+inf表示最後一個成員,limit後面的參數用於限制返回成員的數量,
    #2表示從位置索引(0-based)等於2的成員開始,取後面3個成員,類似於MySQL中的limit
    127.0.0.1:6379> zrangebyscore myzset -inf +inf withscores limit 2 3
    1) "three"
    2) "3"
    3) "four"
    4) "4"
    #根據分數刪除成員,刪除分數滿足表達式1 <= score <= 2的成員,並返回實際刪除的數量
    127.0.0.1:6379> zremrangebyscore myzset 1 2
    (integer) 2
    #看出一下上面的刪除是否成功
    127.0.0.1:6379> zrange myzset 0 -1
    1) "three"
    2) "four"
    #根據索引刪除成員,刪除索引滿足表達式0 <= rank <= 1的成員
    127.0.0.1:6379> zremrangebyrank myzset 0 1
    (integer) 2
    #查看上一條命令是否刪除成功
    127.0.0.1:6379> zcard myzset
    (integer) 0
  • zrevrange/zrevrangebyscore/zrevrank

    127.0.0.1:6379> del myzset
    (integer) 0
    127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
    (integer) 4
    #按索引從高到低的方式獲取成員
    127.0.0.1:6379> zrevrange myzset 0 -1 WITHSCORES
    1) "four"
    2) "4"
    3) "three"
    4) "3"
    5) "two"
    6) "2"
    7) "one"
    8) "1"
    #由於是從高到低的排序,所以位置等於0的是four,1是three,並以此類推
    127.0.0.1:6379> zrevrange myzset 1 3
    1) "three"
    2) "two"
    3) "one"
    #按索引從高到低的方式根據分數獲取成員,分數滿足表達式3 >= score >= 0的成員
    127.0.0.1:6379> zrevrangebyscore myzset 3 0
    1) "three"
    2) "two"
    3) "one"
    #limit選項的含義等同於zrangebyscore中的該選項,只是在計算位置時按照相反的順序計算和獲取
    127.0.0.1:6379> zrevrangebyscore myzset 4 0 limit 1 2
    1) "three"
    2) "two"
    #獲取成員one在集合中的索引,由於是從高到低的排序,所以one的位置是3
    127.0.0.1:6379> zrevrank myzset one
    (integer) 3
    #由於是從高到低的排序,所以four的位置是0
    127.0.0.1:6379> zrevrank myzset four
    (integer) 0

5.3 應用範圍

  1. 可以用於大型在線遊戲的積分排行榜。每當玩家的分數發生變化時,可以執行ZADD命令更新玩家的分數,此後再通過ZRANGE命令獲取積分TOP 10的用戶信息。當然我們也可以利用ZRANK命令通過username來獲取玩家的排行信息。最後我們將組合使用ZRANGE和ZRANK命令快速的獲取和某個玩家積分相近的其他用戶的信息。
  2. Sorted-Sets類型還可用於構建索引數據。

6. Hash(哈希)類型

6.1 概述

可以將Redis中的Hash類型看成具有String Key和String Value的map容器。所以該類型非常適合於存儲值對象的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那麽該類型的數據也將僅占用很少的磁盤空間。每一個Hash可以存儲4294967295個鍵值對。

6.2 操作

  • hset/hget/hlen/hexists/hdel/hsetnx

    #給鍵值為myhash的鍵設置字段為field1,值為itany
    127.0.0.1:6379> hset myhash field1 "itany"
    (integer) 1
    #獲取鍵值為myhash,字段為field1的值
    127.0.0.1:6379> hget myhash field1
    "itany"
    #myhash鍵中不存在field2字段,因此返回nil
    127.0.0.1:6379> hget myhash field2
    (nil)
    #給myhash關聯的Hashes值添加一個新的字段field2,其值為liu
    127.0.0.1:6379> hset myhash field2 "liu"
    (integer) 1
    #獲取myhash鍵的字段數量
    127.0.0.1:6379> hlen myhash
    (integer) 2
    #判斷myhash鍵中是否存在字段名為field1的字段,由於存在,返回值為1
    127.0.0.1:6379> hexists myhash field1
    (integer) 1
    #刪除myhash鍵中字段名為field1的字段,刪除成功返回1
    127.0.0.1:6379> hdel myhash field1
    (integer) 1
    #再次刪除myhash鍵中字段名為field1的字段,由於上一條命令已經將其刪除,因為沒有刪除,返回0
    127.0.0.1:6379> hdel myhash field1
    (integer) 0
    #通過hsetnx命令給myhash添加新字段field1,其值為itany,因為該字段已經被刪除,所以該命令添加成功並返回1
    127.0.0.1:6379> hsetnx myhash field1 "itany"
    (integer) 1
    #由於myhash的field1字段已經通過上一條命令添加成功,因為本條命令不做任何操作後返回0
    127.0.0.1:6379> hsetnx myhash field1 "itany"
    (integer) 0
    
  • hincrby

    127.0.0.1:6379> del myhash
    (integer) 1
    #準備測試數據
    127.0.0.1:6379> hset myhash field 5
    (integer) 1
    #給myhash的field字段的值加1,返回加後的結果
    127.0.0.1:6379> hincrby myhash field 1
    (integer) 6
    #給myhash的field字段的值加-1,返回加後的結果
    127.0.0.1:6379> hincrby myhash field -1
    (integer) 5
    #給myhash的field字段的值加-10,返回加後的結果
    127.0.0.1:6379> hincrby myhash field -10
    (integer) -5  
  • hmset/hmget/hgetall/hkeys/hvals

    127.0.0.1:6379> del myhash
    (integer) 1
    #為該鍵myhash,一次性設置多個字段,分別是field1 = "hello", field2 = "world"
    127.0.0.1:6379> hmset myhash field1 "hello" field2 "world"
    OK
    #獲取myhash鍵的多個字段,其中field3並不存在,因為在返回結果中與該字段對應的值為nil
    127.0.0.1:6379> hmget myhash field1 field2 field3
    1) "hello"
    2) "world"
    3) (nil)
    #返回myhash鍵的所有字段及其值,從結果中可以看出,他們是逐對列出的
    127.0.0.1:6379> hgetall myhash
    1) "field1"
    2) "hello"
    3) "field2"
    4) "world"
    #僅獲取myhash鍵中所有字段的名字
    127.0.0.1:6379> hkeys myhash
    1) "field1"
    2) "field2"
    #僅獲取myhash鍵中所有字段的值
    127.0.0.1:6379> hvals myhash
    1) "hello"
    2) "world" 

Redis快速入門視頻課程——隨堂筆記(一)