redis WATCH命令介紹

2021-07-10 11:20:48 字數 1782 閱讀 4818

我們已經知道在乙個事務中只有當所有命令都依次執行完後才能得到每個結果的返回值,可是有些情況下需要先獲得一條命令的返回值,然後再根據這個值執行下一條命令。例如,介紹incr命令時曾經說過使用get和set命令自己實現incr函式會出現競態條件,偽**如下:

def incr($key)

$value = get $key

if not $value

$value = 0

$value = $value + 1

set $key, $value

return $value

肯定會有很多讀者想到可以用事務來實現incr函式以防止競態條件,可是因為事務中的每個命令的執行結果都是最後一起返回的,所以無法將前一條命令的結果作為下一條命令的引數,即在執行set命令時無法獲得get命令的返回值,也就無法做到增1的功能了。

為了解決這個問題,我們需要換一種思路。即在 get 獲得鍵值後保證該鍵值不被其他客戶端修改,直到函式執行完成後才允許其他客戶端修改該鍵鍵值,這樣也可以防止競態條件。要實現這一思路需要請出事務家族的另一位成員:watch。watch命令可以監控乙個或多個鍵,一旦其中有乙個鍵被修改(或刪除),之後的事務就不會執行。監控一直持續到exec命令(事務中的命令是在exec之後才執行的,所以在multi命令後可以修改watch監控的鍵值),如:

redis> set key 1

okredis> watch key

okredis> set key 2

okredis> multi

okredis> set key 3

queued

redis> exec

(nil)

redis> get key

"2"上例中在執行watch命令後、事務執行前修改了key的值(即set key 2),所以最後事務中的命令set key 3沒有執行,exec命令返回空結果。

學會了watch命令就可以通過事務自己實現incr函式了,偽**如下:

def incr($key)

watch $key

$value = get $key

if not $value

$value = 0

$value = $value + 1

multi

set $key, $value

result = exec

return result[0]

因為exec命令返回值是多行字串型別,所以**中使用result[0]來獲得其中第乙個結果。

提示  由於watch命令的作用只是當被監控的鍵值被修改後阻止之後乙個事務的執行,而不能保證其他客戶端不修改這一鍵值,所以我們需要在exec執行失敗後重新執行整個函式。

執行exec命令後會取消對所有鍵的監控,如果不想執行事務中的命令也可以使用unwatch命令來取消監控。比如,我們要實現hsetxx函式,作用與hsetnx命令類似,只不過是僅當欄位存在時才賦值。為了避免競態條件我們使用事務來完成這一功能:

def hsetxx($key, $field, $value)

watch $key

$isfieldexists = hexists $key, $field

if $isfieldexists is 1

multi

hset $key, $field, $value

exec

else

unwatch

return $isfieldexists

在**中會判斷要賦值的字段是否存在,如果欄位不存在的話就不執行事務中的命令,但需要使用unwatch命令來保證下乙個事務的執行不會受到影響。

如何使用Redis Watch命令

使用redis管理資料,理解如何使用事務儲存鍵值對資料很重要。redis事務與rdmms事務有些類似,但也有差異。redis主要通過幾個命令有效管理事務,本文討論redis的watch命令以及如何使用。在閱讀之前你最好安裝好redis環境,熟悉redis常用命令。redis事務命令主要包括 watc...

php使用redis watch秒殺搶購

redis的watch multi exec 方法實現秒殺搶購。優點 使用了樂觀鎖沒有鎖的等待,比佇列方式減少了大量的記憶體消耗。watch 監視乙個或多個key,如果在事務執行之前這個 或這些 key被其他命令所改動,那麼事務將被打斷.redis new redis result redis co...

使用redis watch實現秒殺搶購,避免超賣

涉及搶購 秒殺 搶票等活動時,為了避免超賣,那麼庫存數量是有限的,但是如果同時下單人數超過了庫存數量,就會導致商品超賣問題。那麼我們怎麼來解決這個問題呢?header content type text html charset utf 8 redis new redis result redis ...