天天看點

redis指令詳解與使用場景舉例——String

APPEND key value

如果 key 已經存在并且是一個字元串, APPEND 指令将 value 追加到 key 原來的值的末尾。

如果 key 不存在, APPEND 就簡單地将給定 key 設為 value ,就像執行 SET key value 一樣。

可用版本:

2.0.0+

時間複雜度:

平攤O(1)

傳回值:

追加 value 之後, key 中字元串的長度。

對不存在的 key 執行 APPEND

redis> EXISTS myphone               # 確定 myphone 不存在
(integer) 
redis> APPEND myphone "nokia"       # 對不存在的 key 進行 APPEND ,等同于 SET myphone "nokia"
(integer)                          # 字元長度
           
對已存在的字元串進行 APPEND
redis> APPEND myphone " - 1110"     # 長度從 5 個字元增加到 12 個字元
(integer) 
redis> GET myphone
"nokia - 1110"
           

時間序列(Time series)

APPEND 可以為一系列定長(fixed-size)資料(sample)提供一種緊湊的表示方式,通常稱之為時間序列。

每當一個新資料到達的時候,執行以下指令:

APPEND timeseries “fixed-size sample”

然後可以通過以下的方式通路時間序列的各項屬性:

● STRLEN 給出時間序列中資料的數量

● GETRANGE 可以用于随機通路。隻要有相關的時間資訊的話,我們就可以在 Redis 2.6 中使用 Lua 腳本和 GETRANGE 指令實作二分查找。

● SETRANGE 可以用于覆寫或修改已存在的的時間序列。

這個模式的唯一缺陷是我們隻能增長時間序列,而不能對時間序列進行縮短,因為 Redis 目前還沒有對字元串進行修剪(tirm)的指令,但是,不管怎麼說,這個模式的儲存方式還是可以節省下大量的空間。

可以考慮使用 UNIX 時間戳作為時間序列的鍵名,這樣一來,可以避免單個 key 因為儲存過大的時間序列而占用大量記憶體,另一方面,也可以節省下大量命名空間。

redis> APPEND ts "0043"
(integer) 
redis> APPEND ts "0035"
(integer) 
redis> GETRANGE ts  
"0043"
redis> GETRANGE ts  
"0035"
           

BITCOUNT key [start] [end]

計算給定字元串中,被設定為 1 的比特位的數量。

一般情況下,給定的整個字元串都會被進行計數,通過指定額外的 start 或 end 參數,可以讓計數隻在特定的位上進行。

start 和 end 參數的設定和 GETRANGE 指令類似,都可以使用負數值:比如 -1 表示最後一個位,而 -2 表示倒數第二個位,以此類推。

不存在的 key 被當成是空字元串來處理,是以對一個不存在的 key 進行 BITCOUNT 操作,結果為 0 。

可用版本:

2.6.0+

時間複雜度:

O(N)

傳回值:

被設定為 1 的位的數量。

redis> BITCOUNT bits
(integer) 
redis> SETBIT bits            # 0001
(integer) 
redis> BITCOUNT bits
(integer) 
redis> SETBIT bits            # 1001
(integer) 
redis> BITCOUNT bits
(integer) 
           

模式:使用 bitmap 實作使用者簽到次數統計

Bitmap 對于一些特定類型的計算非常有效。

Bitmap 對于一些特定類型的計算非常有效。

假設現在我們希望記錄自己網站上的使用者的上線頻率,比如說,計算使用者 A 上線了多少天,使用者 B 上線了多少天,諸如此類,以此作為資料,進而決定讓哪些使用者參加 beta 測試等活動 —— 這個模式可以使用 SETBIT 和 BITCOUNT 來實作。

比如說,每當使用者在某一天上線的時候,我們就使用 SETBIT ,以使用者名作為 key ,将那天所代表的網站的上線日作為 offset 參數,并将這個 offset 上的為設定為 1 。

舉個例子,如果今天是網站上線的第 100 天,而使用者 peter 在今天閱覽過網站,那麼執行指令 SETBIT peter 100 1 ;如果明天 peter 也繼續閱覽網站,那麼執行指令 SETBIT peter 101 1 ,以此類推。

當要計算 peter 總共以來的上線次數時,就使用 BITCOUNT 指令:執行 BITCOUNT peter ,得出的結果就是 peter 上線的總天數。

性能

前面的上線次數統計例子,即使運作 10 年,占用的空間也隻是每個使用者 10*365 比特位(bit),也即是每個使用者 456 位元組。對于這種大小的資料來說, BITCOUNT 的處理速度就像 GET 和 INCR 這種 O(1) 複雜度的操作一樣快。

如果你的 bitmap 資料非常大,那麼可以考慮使用以下兩種方法:

1. 将一個大的 bitmap 分散到不同的 key 中,作為小的 bitmap 來處理。使用 Lua 腳本可以很友善地完成這一工作。

2. 使用 BITCOUNT 的 start 和 end 參數,每次隻對所需的部分位進行計算,将位的累積工作(accumulating)放到用戶端進行,并且對結果進行緩存 (caching)。

BITOP operation destkey key [key …]

對一個或多個儲存二進制位的字元串 key 進行位元操作,并将結果儲存到 destkey 上。

operation 可以是 AND 、 OR 、 NOT 、 XOR 這四種操作中的任意一種:

● BITOP AND destkey key [key …] ,對一個或多個 key 求邏輯并,并将結果儲存到 destkey 。

● BITOP OR destkey key [key …] ,對一個或多個 key 求邏輯或,并将結果儲存到 destkey 。

● BITOP XOR destkey key [key …] ,對一個或多個 key 求邏輯異或,并将結果儲存到 destkey 。

● BITOP NOT destkey key ,對給定 key 求邏輯非,并将結果儲存到 destkey 。

除了 NOT 操作之外,其他操作都可以接受一個或多個 key 作為輸入。

處理不同長度的字元串

當 BITOP 處理不同長度的字元串時,較短的那個字元串所缺少的部分會被看作 0 。

空的 key 也被看作是包含 0 的字元串序列。

可用版本:

2.6.0+

時間複雜度:

O(N)

傳回值:

儲存到 destkey 的字元串的長度,和輸入 key 中最長的字元串長度相等。

BITOP 的複雜度為 O(N) ,當處理大型矩陣(matrix)或者進行大資料量的統計時,最好将任務指派到附屬節點(slave)進行,避免阻塞主節點。

redis> SETBIT bits-          # bits-1 = 1001
(integer) 
redis> SETBIT bits-  
(integer) 
redis> SETBIT bits-          # bits-2 = 1011
(integer) 
redis> SETBIT bits-  
(integer) 
redis> SETBIT bits-  
(integer) 
redis> BITOP AND and-result bits- bits-
(integer) 
redis> GETBIT and-result       # and-result = 1001
(integer) 
redis> GETBIT and-result 
(integer) 
redis> GETBIT and-result 
(integer) 
redis> GETBIT and-result 
(integer) 
           

DECR key

将 key 中儲存的數字值減一。

如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 DECR 操作。

如果值包含錯誤的類型,或字元串類型的值不能表示為數字,那麼傳回一個錯誤。

本操作的值限制在 64 位(bit)有符号數字表示之内。

關于遞增(increment) / 遞減(decrement)操作的更多資訊,請參見 INCR 指令。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

執行 DECR 指令之後 key 的值。

對存在的數字值 key 進行 DECR

redis> SET failure_times 
OK
redis> DECR failure_times
(integer) 
對不存在的 key 值進行 DECR
redis> EXISTS count
(integer) 
redis> DECR count
(integer) -
           
對存在但不是數值的 key 進行 DECR
redis> SET company YOUR_CODE_SUCKS.LLC
OK
redis> DECR company
(error) ERR value is not an integer or out of range
           

DECRBY key decrement

将 key 所儲存的值減去減量 decrement 。

如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 DECRBY 操作。

如果值包含錯誤的類型,或字元串類型的值不能表示為數字,那麼傳回一個錯誤。

本操作的值限制在 64 位(bit)有符号數字表示之内。

關于更多遞增(increment) / 遞減(decrement)操作的更多資訊,請參見

INCR 指令。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

減去 decrement 之後, key 的值。

對已存在的 key 進行 DECRBY

redis> SET count 
OK
redis> DECRBY count 
(integer) 
對不存在的 key 進行DECRBY
redis> EXISTS pages
(integer) 
redis> DECRBY pages 
(integer) -
           

GET key

傳回 key 所關聯的字元串值。

如果 key 不存在那麼傳回特殊值 nil 。

假如 key 儲存的值不是字元串類型,傳回一個錯誤,因為 GET 隻能用于處理字元串值。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

當 key 不存在時,傳回 nil ,否則,傳回 key 的值。

如果 key 不是字元串類型,那麼傳回一個錯誤。

對不存在的 key 或字元串類型 key 進行 GET

redis> GET db
(nil)
redis> SET db redis
OK
redis> GET db
"redis"
對不是字元串類型的 key 進行 GET
redis> DEL db
(integer) 
redis> LPUSH db redis mongodb mysql
(integer) 
redis> GET db
(error) ERR Operation against a key holding the wrong kind of value
           

GETBIT key offset

對 key 所儲存的字元串值,擷取指定偏移量上的位(bit)。

當 offset 比字元串值的長度大,或者 key 不存在時,傳回 0 。

可用版本:

2.2.0+

時間複雜度:

O(1)

傳回值:

字元串值指定偏移量上的位(bit)。

對不存在的 key 或者不存在的 offset 進行 GETBIT, 傳回 0

redis> EXISTS bit

(integer) 0

redis> GETBIT bit 10086

(integer) 0

對已存在的 offset 進行 GETBIT

redis> SETBIT bit 10086 1

(integer) 0

redis> GETBIT bit 10086

(integer) 1

GETRANGE key start end

傳回 key 中字元串值的子字元串,字元串的截取範圍由 start 和 end 兩個偏移量決定(包括 start 和 end 在内)。

負數偏移量表示從字元串最後開始計數, -1 表示最後一個字元, -2 表示倒數第二個,以此類推。

GETRANGE 通過保證子字元串的值域(range)不超過實際字元串的值域來處理超出範圍的值域請求。

在 <= 2.0 的版本裡,GETRANGE 被叫作 SUBSTR。

可用版本:

2.4.0+

時間複雜度:

O(N), N 為要傳回的字元串的長度。

複雜度最終由字元串的傳回值長度決定,但因為從已有字元串中取出子字元串的操作非常廉價(cheap),是以對于長度不大的字元串,該操作的複雜度也可看作O(1)。

傳回值:

截取得出的子字元串。

redis> SET greeting "hello, my friend"
OK
redis> GETRANGE greeting            # 傳回索引-的字元,包括。
"hello"
redis> GETRANGE greeting - -        # 不支援回繞操作
""
redis> GETRANGE greeting - -        # 負數索引
"end"
redis> GETRANGE greeting  -         # 從第一個到最後一個
"hello, my friend"
redis> GETRANGE greeting      # 值域範圍不超過實際字元串,超過部分自動被符略
"hello, my friend"
           

GETSET key value

将給定 key 的值設為 value ,并傳回 key 的舊值(old value)。

當 key 存在但不是字元串類型時,傳回一個錯誤。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

傳回給定 key 的舊值。

當 key 沒有舊值時,也即是, key 不存在時,傳回 nil 。

redis> GETSET db mongodb    # 沒有舊值,傳回 nil
(nil)
redis> GET db
"mongodb"
redis> GETSET db redis      # 傳回舊值 mongodb
"mongodb"
redis> GET db
"redis"
           

模式

GETSET 可以和 INCR 組合使用,實作一個有原子性(atomic)複位操作的計數器(counter)。

舉例來說,每次當某個事件發生時,程序可能對一個名為 mycount 的 key 調用 INCR 操作,通常我們還要在一個原子時間内同時完成獲得計數器的值和将計數器值複位為 0 兩個操作。

可以用指令 GETSET mycounter 0 來實作這一目标。

redis> INCR mycount
(integer) 
redis> GETSET mycount   # 一個原子内完成 GET mycount 和 SET mycount 0 操作
"11"
redis> GET mycount       # 計數器被重置
"0"
           

INCR key

将 key 中儲存的數字值增一。

如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCR 操作。

如果值包含錯誤的類型,或字元串類型的值不能表示為數字,那麼傳回一個錯誤。

本操作的值限制在 64 位(bit)有符号數字表示之内。

這是一個針對字元串的操作,因為 Redis 沒有專用的整數類型,是以 key 内儲存的字元串被解釋為十進制 64 位有符号整數來執行 INCR 操作。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

執行 INCR 指令之後 key 的值。

redis> SET page_view 
OK
redis> INCR page_view
(integer) 
redis> GET page_view    # 數字值在 Redis 中以字元串的形式儲存
"21"
           

模式:計數器

計數器是 Redis 的原子性自增操作可實作的最直覺的模式了,它的想法相當簡單:每當某個操作發生時,向 Redis 發送一個 INCR 指令。

比如在一個 web 應用程式中,如果想知道使用者在一年中每天的點選量,那麼隻要将使用者 ID 以及相關的日期資訊作為鍵,并在每次使用者點選頁面時,執行一次自增操作即可。

比如使用者名是 peter ,點選時間是 2012 年 3 月 22 日,那麼執行指令 INCR peter::2012.3.22 。

可以用以下幾種方式擴充這個簡單的模式:

● 可以通過組合使用 INCR 和 EXPIRE ,來達到隻在規定的生存時間内進行計數(counting)的目的。

● 用戶端可以通過使用 GETSET 指令原子性地擷取計數器的目前值并将計數器清零,更多資訊請參考 GETSET 指令。

● 使用其他自增/自減操作,比如 DECR 和 INCRBY ,使用者可以通過執行不同的操作增加或減少計數器的值,比如在遊戲中的記分器就可能用到這些指令。

模式:限速器

限速器是特殊化的電腦,它用于限制一個操作可以被執行的速率(rate)。

限速器的典型用法是限制公開 API 的請求次數,以下是一個限速器實作示例,它将 API 的最大請求數限制在每個 IP 位址每秒鐘十個之内:

FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
current = GET(keyname)
IF current != NULL AND current >  THEN
    ERROR "too many requests per second"
END
IF current == NULL THEN
    MULTI
        INCR(keyname, )
        EXPIRE(keyname, )
    EXEC
ELSE
    INCR(keyname, )
END
PERFORM_API_CALL()
           

這個實作每秒鐘為每個 IP 位址使用一個不同的計數器,并用 EXPIRE 指令設定生存時間(這樣 Redis 就會負責自動删除過期的計數器)。

注意,我們使用事務打包執行 INCR 指令和 EXPIRE 指令,避免引入競争條件,保證每次調用 API 時都可以正确地對計數器進行自增操作并設定生存時間。

以下是另一個限速器實作:

FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current >  THEN
    ERROR "too many requests per second"
ELSE
    value = INCR(ip)
    IF value ==  THEN
        EXPIRE(ip,)
    END
    PERFORM_API_CALL()
END
           

這個限速器隻使用單個計數器,它的生存時間為一秒鐘,如果在一秒鐘内,這個計數器的值大于 10 的話,那麼通路就會被禁止。

這個新的限速器在思路方面是沒有問題的,但它在實作方面不夠嚴謹,如果我們仔細觀察一下的話,就會發現在 INCR 和 EXPIRE 之間存在着一個競争條件,假如用戶端在執行 INCR 之後,因為某些原因(比如用戶端失敗)而忘記設定 EXPIRE 的話,那麼這個計數器就會一直存在下去,造成每個使用者隻能通路 10 次,噢,這簡直是個災難!

要消滅這個實作中的競争條件,我們可以将它轉化為一個 Lua 腳本,并放到 Redis 中運作(這個方法僅限于 Redis 2.6 及以上的版本):

local current
current = redis.call("incr",KEYS[])
if tonumber(current) ==  then
    redis.call("expire",KEYS[],)
end
           

通過将計數器作為腳本放到 Redis 上運作,我們保證了 INCR 和 EXPIRE 兩個操作的原子性,現在這個腳本實作不會引入競争條件,它可以運作的很好。

關于在 Redis 中運作 Lua 腳本的更多資訊,請參考 EVAL 指令。

還有另一種消滅競争條件的方法,就是使用 Redis 的清單結構來代替 INCR 指令,這個方法無須腳本支援,是以它在 Redis 2.6 以下的版本也可以運作得很好:

FUNCTION LIMIT_API_CALL(ip)
current = LLEN(ip)
IF current >  THEN
    ERROR "too many requests per second"
ELSE
    IF EXISTS(ip) == FALSE
        MULTI
            RPUSH(ip,ip)
            EXPIRE(ip,)
        EXEC
    ELSE
        RPUSHX(ip,ip)
    END
    PERFORM_API_CALL()
END
           

新的限速器使用了清單結構作為容器, LLEN 用于對通路次數進行檢查,一個事務包裹着 RPUSH 和 EXPIRE 兩個指令,用于在第一次執行計數時建立清單,并正确設定地設定過期時間,最後, RPUSHX 在後續的計數操作中進行增加操作。

INCRBY key increment

将 key 所儲存的值加上增量 increment 。

如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCRBY 指令。

如果值包含錯誤的類型,或字元串類型的值不能表示為數字,那麼傳回一個錯誤。

本操作的值限制在 64 位(bit)有符号數字表示之内。

關于遞增(increment) / 遞減(decrement)操作的更多資訊,參見 INCR 指令。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

加上 increment 之後, key 的值。

key 存在且是數字值

redis> SET rank 
OK
redis> INCRBY rank 
(integer) 
redis> GET rank
"70"
 key 不存在時
redis> EXISTS counter
(integer) 
redis> INCRBY counter 
(integer) 
redis> GET counter
"30"
 key 不是數字值時
redis> SET book "long long ago..."
OK
redis> INCRBY book 
(error) ERR value is not an integer or out of range
           

INCRBYFLOAT key increment

為 key 中所儲存的值加上浮點數增量 increment 。

如果 key 不存在,那麼 INCRBYFLOAT 會先将 key 的值設為 0 ,再執行加法操作。

如果指令執行成功,那麼 key 的值會被更新為(執行加法之後的)新值,并且新值會以字元串的形式傳回給調用者。

無論是 key 的值,還是增量 increment ,都可以使用像 2.0e7 、 3e5 、 90e-2 那樣的指數符号(exponential notation)來表示,但是,執行 INCRBYFLOAT 指令之後的值總是以同樣的形式儲存,也即是,它們總是由一個數字,一個(可選的)小數點和一個任意位的小數部分組成(比如 3.14 、 69.768 ,諸如此類),小數部分尾随的 0 會被移除,如果有需要的話,還會将浮點數改為整數(比如 3.0 會被儲存成 3 )。

除此之外,無論加法計算所得的浮點數的實際精度有多長, INCRBYFLOAT 的計算結果也最多隻能表示小數點的後十七位。

當以下任意一個條件發生時,傳回一個錯誤:

● key 的值不是字元串類型(因為 Redis 中的數字和浮點數都以字元串的形式儲存,是以它們都屬于字元串類型)

● key 目前的值或者給定的增量 increment 不能解釋(parse)為雙精度浮點數(double precision floating point number)

可用版本:

2.6.0+

時間複雜度:

O(1)

傳回值:

執行指令之後 key 的值。

值和增量都不是指數符号

redis> SET mykey 
OK
redis> INCRBYFLOAT mykey 
"10.6"
 值和增量都是指數符号
redis> SET mykey 
OK
redis> GET mykey                # 用 SET 設定的值可以是指數符号
"314e-2"
redis> INCRBYFLOAT mykey       # 但執行 INCRBYFLOAT 之後格式會被改成非指數符号
"3.14"
可以對整數類型執行
redis> SET mykey 
OK
redis> INCRBYFLOAT mykey 
"4.1"
後跟的  會被移除
redis> SET mykey 
OK
redis> GET mykey                                    # SET 設定的值小數部分可以是 0
"3.0"
redis> INCRBYFLOAT mykey     # 但 INCRBYFLOAT 會将無用的 0 忽略掉,有需要的話,将浮點變為整數
"4"
redis> GET mykey
"4"
           

MGET key [key …]

傳回所有(一個或多個)給定 key 的值。

如果給定的 key 裡面,有某個 key 不存在,那麼這個 key 傳回特殊值 nil 。是以,該指令永不失敗。

可用版本:

1.0.0+

時間複雜度:

O(N) , N 為給定 key 的數量。

傳回值:

一個包含所有給定 key 的值的清單。

redis> SET redis redis.com
OK
redis> SET mongodb mongodb.org
OK
redis> MGET redis mongodb
) "redis.com"
) "mongodb.org"
redis> MGET redis mongodb mysql     # 不存在的 mysql 傳回 nil
) "redis.com"
) "mongodb.org"
) (nil)
           

MSET key value [key value …]

同時設定一個或多個 key-value 對。

如果某個給定 key 已經存在,那麼 MSET 會用新值覆寫原來的舊值,如果這不是你所希望的效果,請考慮使用 MSETNX 指令:它隻會在所有給定 key 都不存在的情況下進行設定操作。

MSET 是一個原子性(atomic)操作,所有給定 key 都會在同一時間内被設定,某些給定 key 被更新而另一些給定 key 沒有改變的情況,不可能發生。

可用版本:

1.0.1+

時間複雜度:

O(N), N 為要設定的 key 數量。

傳回值:

總是傳回 OK (因為 MSET 不可能失敗)

redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
OK
redis> MGET date time weather
) "2012.3.30"
) "11:00 a.m."
) "sunny"
MSET 覆寫舊值例子
redis> SET google "google.hk"
OK
redis> MSET google "google.com"
OK
redis> GET google
"google.com"
           

MSETNX key value [key value …]

同時設定一個或多個 key-value 對,當且僅當所有給定 key 都不存在。

即使隻有一個給定 key 已存在, MSETNX 也會拒絕執行所有給定 key 的設定操作。

MSETNX 是原子性的,是以它可以用作設定多個不同 key 表示不同字段(field)的唯一性邏輯對象(unique logic object),所有字段要麼全被設定,要麼全不被設定。

可用版本:

1.0.1+

時間複雜度:

O(N), N 為要設定的 key 的數量。

傳回值:

當所有 key 都成功設定,傳回 1 。

如果所有給定 key 都設定失敗(至少有一個 key 已經存在),那麼傳回 0 。

對不存在的 key 進行 MSETNX

redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis"
(integer) 
redis> MGET rmdbs nosql key-value-store
) "MySQL"
) "MongoDB"
) "redis"
           

MSET 的給定 key 當中有已存在的 key

redis> MSETNX rmdbs "Sqlite" language "python"  # rmdbs 鍵已經存在,操作失敗
(integer) 
redis> EXISTS language                          # 因為 MSET 是原子性操作,language 沒有被設定
(integer) 
redis> GET rmdbs                                # rmdbs 也沒有被修改
"MySQL"
           

PSETEX key milliseconds value

這個指令和 SETEX 指令相似,但它以毫秒為機關設定 key 的生存時間,而不是像 SETEX 指令那樣,以秒為機關。

可用版本:

2.6.0+

時間複雜度:

O(1)

傳回值:

設定成功時傳回 OK 。

redis> PSETEX mykey  "Hello"
OK
redis> PTTL mykey
(integer) 
redis> GET mykey
"Hello"
           

SET key value [EX seconds] [PX milliseconds] [NX|XX]

将字元串值 value 關聯到 key 。

如果 key 已經持有其他值, SET 就覆寫舊值,無視類型。

對于某個原本帶有生存時間(TTL)的鍵來說, 當 SET 指令成功在這個鍵上執行時, 這個鍵原有的 TTL 将被清除。

可選參數

從 Redis 2.6.12 版本開始, SET 指令的行為可以通過一系列參數來修改:

● EX second :設定鍵的過期時間為 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。

● PX millisecond :設定鍵的過期時間為 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。

● NX :隻在鍵不存在時,才對鍵進行設定操作。 SET key value NX 效果等同于 SETNX key value 。

● XX :隻在鍵已經存在時,才對鍵進行設定操作。

因為 SET 指令可以通過參數來實作和 SETNX 、 SETEX 和 PSETEX 三個指令的效果,是以将來的 Redis 版本可能會廢棄并最終移除SETNX 、 SETEX 和 PSETEX 這三個指令。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

在 Redis 2.6.12 版本以前, SET 指令總是傳回 OK 。

從 Redis 2.6.12 版本開始, SET 在設定操作成功完成時,才傳回 OK 。

如果設定了 NX 或者 XX ,但因為條件沒達到而造成設定操作未執行,那麼指令傳回空批量回複(NULL Bulk Reply)。

對不存在的鍵進行設定

redis :> SET key "value"
OK
redis :> GET key
"value"
對已存在的鍵進行設定
redis :> SET key "new-value"
OK
redis :> GET key
"new-value"
           

使用 EX 選項

redis :> SET key-with-expire-time "hello" EX 
OK
redis :> GET key-with-expire-time
"hello"
redis :> TTL key-with-expire-time
(integer) 
           

使用 PX 選項

redis :> SET key-with-pexpire-time "moto" PX 
OK
redis :> GET key-with-pexpire-time
"moto"
redis :> PTTL key-with-pexpire-time
(integer) 
 使用 NX 選項
redis :> SET not-exists-key "value" NX
OK      # 鍵不存在,設定成功
redis :> GET not-exists-key
"value"
redis :> SET not-exists-key "new-value" NX
(nil)   # 鍵已經存在,設定失敗
redis :> GEt not-exists-key
"value" # 維持原值不變
使用 XX 選項
redis :> EXISTS exists-key
(integer) 
redis :> SET exists-key "value" XX
(nil)   # 因為鍵不存在,設定失敗
redis :> SET exists-key "value"
OK      # 先給鍵設定一個值
redis :> SET exists-key "new-value" XX
OK      # 設定新值成功
redis :> GET exists-key
"new-value"
NX 或 XX 可以和 EX 或者 PX 組合使用
redis :> SET key-with-expire-and-NX "hello" EX  NX
OK
redis :> GET key-with-expire-and-NX
"hello"
redis :> TTL key-with-expire-and-NX
(integer) 
redis :> SET key-with-pexpire-and-XX "old value"
OK
redis :> SET key-with-pexpire-and-XX "new value" PX 
OK
redis :> GET key-with-pexpire-and-XX
"new value"
redis :> PTTL key-with-pexpire-and-XX
(integer) 
EX 和 PX 可以同時出現,但後面給出的選項會覆寫前面給出的選項
redis :> SET key "value" EX  PX 
OK
redis :> TTL key
(integer)   # 這是 PX 參數設定的值
redis :> SET another-key "value" PX  EX 
OK
redis :> TTL another-key
(integer)    # 這是 EX 參數設定的值
           

使用模式

指令 SET resource-name anystring NX EX max-lock-time 是一種在 Redis 中實作鎖的簡單方法。

用戶端執行以上的指令:

● 如果伺服器傳回 OK ,那麼這個用戶端獲得鎖。

● 如果伺服器傳回 NIL ,那麼用戶端擷取鎖失敗,可以在稍後再重試。

設定的過期時間到達之後,鎖将自動釋放。

可以通過以下修改,讓這個鎖實作更健壯:

● 不使用固定的字元串作為鍵的值,而是設定一個不可猜測(non-guessable)的長随機字元串,作為密碼串(token)。

● 不使用 DEL 指令來釋放鎖,而是發送一個 Lua 腳本,這個腳本隻在用戶端傳入的值和鍵的密碼串相比對時,才對鍵進行删除。

這兩個改動可以防止持有過期鎖的用戶端誤删現有鎖的情況出現。

以下是一個簡單的解鎖腳本示例:

if redis.call("get",KEYS[]) == ARGV[]
then
    return redis.call("del",KEYS[])
else
    return 
end
           

這個腳本可以通過 EVAL …script… 1 resource-name token-value 指令來調用。

SETBIT key offset value

對 key 所儲存的字元串值,設定或清除指定偏移量上的位(bit)。

位的設定或清除取決于 value 參數,可以是 0 也可以是 1 。

當 key 不存在時,自動生成一個新的字元串值。

字元串會進行伸展(grown)以確定它可以将 value 儲存在指定的偏移量上。當字元串值進行伸展時,空白位置以 0 填充。

offset 參數必須大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。

對使用大的 offset 的 SETBIT 操作來說,記憶體配置設定可能造成 Redis 伺服器被阻塞。具體參考 SETRANGE 指令,warning(警告)部分。

可用版本:

2.2.0+

時間複雜度:

O(1)

傳回值:

指定偏移量原來儲存的位。

redis> SETBIT bit  
(integer) 
redis> GETBIT bit 
(integer) 
redis> GETBIT bit    # bit 預設被初始化為 
(integer) 
           

SETEX key seconds value

将值 value 關聯到 key ,并将 key 的生存時間設為 seconds (以秒為機關)。

如果 key 已經存在, SETEX 指令将覆寫舊值。

這個指令類似于以下兩個指令:

SET key value

EXPIRE key seconds # 設定生存時間

不同之處是, SETEX 是一個原子性(atomic)操作,關聯值和設定生存時間兩個動作會在同一時間内完成,該指令在 Redis 用作緩存時,非常實用。

可用版本:

2.0.0+

時間複雜度:

O(1)

傳回值:

設定成功時傳回 OK 。

當 seconds 參數不合法時,傳回一個錯誤。

在 key 不存在時進行 SETEX

redis> SETEX cache_user_id  
OK
redis> GET cache_user_id  # 值
"10086"
redis> TTL cache_user_id  # 剩餘生存時間
(integer) 
key 已經存在時,SETEX 覆寫舊值
redis> SET cd "timeless"
OK
redis> SETEX cd  "goodbye my love"
OK
redis> GET cd
"goodbye my love"
redis> TTL cd
(integer) 
           

SETNX key value

将 key 的值設為 value ,當且僅當 key 不存在。

若給定的 key 已經存在,則 SETNX 不做任何動作。

SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。

可用版本:

1.0.0+

時間複雜度:

O(1)

傳回值:

設定成功,傳回 1 。

設定失敗,傳回 0 。

redis> EXISTS job                # job 不存在
(integer) 
redis> SETNX job "programmer"    # job 設定成功
(integer) 
redis> SETNX job "code-farmer"   # 嘗試覆寫 job ,失敗
(integer) 
redis> GET job                   # 沒有被覆寫
"programmer"
           

SETRANGE key offset value

用 value 參數覆寫(overwrite)給定 key 所儲存的字元串值,從偏移量 offset 開始。

不存在的 key 當作空白字元串處理。

SETRANGE 指令會確定字元串足夠長以便将 value 設定在指定的偏移量上,如果給定 key 原來儲存的字元串長度比偏移量小(比如字元串隻有 5 個字元長,但你設定的 offset 是 10 ),那麼原字元和偏移量之間的空白将用零位元組(zerobytes, “\x00” )來填充。

注意你能使用的最大偏移量是 2^29-1(536870911) ,因為 Redis 字元串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比這更大的空間,你可以使用多個 key 。

當生成一個很長的字元串時,Redis 需要配置設定記憶體空間,該操作有時候可能會造成伺服器阻塞(block)。在2010年的Macbook Pro上,設定偏移量為 536870911(512MB 記憶體配置設定),耗費約 300 毫秒, 設定偏移量為 134217728(128MB 記憶體配置設定),耗費約 80 毫秒,設定偏移量 33554432(32MB 記憶體配置設定),耗費約 30 毫秒,設定偏移量為 8388608(8MB 記憶體配置設定),耗費約 8 毫秒。 注意若首次記憶體配置設定成功之後,再對同一個 key 調用 SETRANGE 操作,無須再重新記憶體。

可用版本:

2.2.0+

時間複雜度:

對小(small)的字元串,平攤複雜度O(1)。(關于什麼字元串是”小”的,請參考 APPEND 指令)

否則為O(M), M 為 value 參數的長度。

傳回值:

被 SETRANGE 修改之後,字元串的長度。

對非空字元串進行 SETRANGE

redis> SET greeting "hello world"
OK
redis> SETRANGE greeting  "Redis"
(integer) 
redis> GET greeting
"hello Redis"
對空字元串/不存在的 key 進行 SETRANGE
redis> EXISTS empty_string
(integer) 
redis> SETRANGE empty_string  "Redis!"   # 對不存在的 key 使用 SETRANGE
(integer) 
redis> GET empty_string                   # 空白處被"\x00"填充
"\x00\x00\x00\x00\x00Redis!"
           

模式

因為有了 SETRANGE 和 GETRANGE 指令,你可以将 Redis 字元串用作具有O(1)随機通路時間的線性數組,這在很多真實用例中都是非常快速且高效的儲存方式,具體請參考 APPEND 指令的『模式:時間序列』部分

STRLEN key

傳回 key 所儲存的字元串值的長度。

當 key 儲存的不是字元串值時,傳回一個錯誤。

可用版本:

2.2.0+

複雜度:

O(1)

傳回值:

字元串值的長度。

當 key 不存在時,傳回 0 。

擷取字元串的長度

redis> SET mykey "Hello world"
OK
redis> STRLEN mykey
(integer) 
不存在的 key 長度為 
redis> STRLEN nonexisting
(integer) 
           

繼續閱讀