redis -- 字符串

1.增

set key value :

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

返回值:

總是返回OK,因爲SET不可能失敗。

setnx key value :

如果key已經存在了,就不做任何操作。

返回:

1或者0


setex key seconds value

將值value關聯到key,並將key的生存時間設爲seconds(以秒爲單位)。如果key存在,就覆寫舊值。

返回值:

設置成功時返回OK

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


mset key value [key value ....]

一個原子操作,新值覆蓋舊值

返回值: 總是返回OK(因爲MSET不可能失敗)


msetnx key value[key value..]

msetnx 是原子操作,如果一個key不存在,就全部不執行

返回值:1或者0




2.刪

del key


3.改

setrange key offset value:

把key的第offset個字符開始,設置爲value,如果key不存在,就創建

返回值:SETRANGE修改之後,字符串的長度。

append key value

在key的基礎上,追加value,如果key不存在,就和set 是一樣的

返回值: 追加value之後,key中字符串的長度。


mset key value [key value ....]

一個原子操作,新值覆蓋舊值

返回值: 總是返回OK(因爲MSET不可能失敗)


getset key value:

設置新值,返回key的舊值。

如果key不存在,返回nil


decr key :

將key的值減一。

如果可以不存在,就以0減一,如果key的value爲str,就報錯,


decrby key decrement :減去decrement

如果key不存在,按照0開始算。如果key的value 是字符串,則報錯。


incr key

incrby key increment 

同上


4.查

get key


mget  key [key....]

如果其中一個key 不存在,則該key返回nil


getrange key start end 

key 不存在 返回“” ,如果超出字符串的長度,就返回字符串本身


strlen key :

不存在key,返回0


exists key:

不存在key,返回0



知識點:

設計模式(Design pattern): 將SETNX用於加鎖(locking)

SETNX可以用作加鎖原語(locking primitive)。比如說,要對關鍵字(key)foo加鎖,客戶端可以嘗試以下方式:

SETNX lock.foo <current Unix time + lock timeout + 1>

如果SETNX返回1,說明客戶端已經獲得了鎖,key設置的unix時間則指定了鎖失效的時間。之後客戶端可以通過DEL lock.foo來釋放鎖。

如果SETNX返回0,說明key已經被其他客戶端上鎖了。如果鎖是非阻塞(non blocking lock)的,我們可以選擇返回調用,或者進入一個重試循環,直到成功獲得鎖或重試超時(timeout)。

處理死鎖(deadlock)

上面的鎖算法有一個問題:如果因爲客戶端失敗、崩潰或其他原因導致沒有辦法釋放鎖的話,怎麼辦?

這種狀況可以通過檢測發現——因爲上鎖的key保存的是unix時間戳,假如key值的時間戳小於當前的時間戳,表示鎖已經不再有效。

但是,當有多個客戶端同時檢測一個鎖是否過期並嘗試釋放它的時候,我們不能簡單粗暴地刪除死鎖的key,再用SETNX上鎖,因爲這時競爭條件(race condition)已經形成了:

  • C1和C2讀取lock.foo並檢查時間戳,SETNX都返回0,因爲它已經被C3鎖上了,但C3在上鎖之後就崩潰(crashed)了。
  • C1向lock.foo發送DEL命令。
  • C1向lock.foo發送SETNX併成功。
  • C2向lock.foo發送DEL命令。
  • C2向lock.foo發送SETNX併成功。
  • 出錯:因爲競爭條件的關係,C1和C2兩個都獲得了鎖。

幸好,以下算法可以避免以上問題。來看看我們聰明的C4客戶端怎麼辦:

  • C4向lock.foo發送SETNX命令。
  • 因爲崩潰掉的C3還鎖着lock.foo,所以Redis向C4返回0
  • C4向lock.foo發送GET命令,查看lock.foo的鎖是否過期。如果不,則休眠(sleep)一段時間,並在之後重試。
  • 另一方面,如果lock.foo內的unix時間戳比當前時間戳老,C4執行以下命令:

GETSET lock.foo <current Unix timestamp + lock timeout + 1>

  • 因爲GETSET的作用,C4可以檢查看GETSET的返回值,確定lock.foo之前儲存的舊值仍是那個過期時間戳,如果是的話,那麼C4獲得鎖。
  • 如果其他客戶端,比如C5,比C4更快地執行了GETSET操作並獲得鎖,那麼C4的GETSET操作返回的就是一個未過期的時間戳(C5設置的時間戳)。C4只好從第一步開始重試。
注意,即便C4的GETSET操作對key進行了修改,這對未來也沒什麼影響。
(這裏是不是有點問題?C4的確是可以重試,但C5怎麼辦?它的鎖的過期被C4修改了。——譯註)

Warning:

爲了讓這個加鎖算法更健壯,獲得鎖的客戶端應該常常檢查過期時間以免鎖因諸如DEL等命令的執行而被意外解開,因爲客戶端失敗的情況非常複雜,不僅僅是崩潰這麼簡單,還可能是客戶端因爲某些操作被阻塞了相當長時間,緊接着DEL命令被嘗試執行(但這時鎖卻在另外的客戶端手上)。



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