1. 程式人生 > >Redis事務和鎖的應用詳解

Redis事務和鎖的應用詳解

一、Redis事務的應用

無論是大小專案還是各種系統,相信事務是不容忽視的,下面,我們對redis的事務展開討論。

如果你比較熟悉mysql的事務,redis的事務那就很簡單了。我們對redis的事務和mysql的事務進行下比較就能更清楚的瞭解到redis的事務機制了。
這裡寫圖片描述

通過比較,我們可以清楚的看到redis的事務命令,先看一段mysql的事務。

start transaction;   -- 開啟事務
update user set money=money-100 where id=1;
.......
commit;   --提交事務

上面是段簡單的mysql事務處理的程式碼,通過這段程式碼我們可以和上面的redis進行比較輕鬆的掌握redis怎麼啟動事務並且如何工作。

redis啟動事務:

multi

當我們通過上面命令啟動事務後,我們就可以根據使用者的操作對事務進行處理。
如果想回滾事務(redis中準確的說是取消事務),可以用下面命令:

discard

如果想提交事務:

exec

那麼,redis中事務是怎樣工作的呢?首先來一個簡單的例項:

這裡寫圖片描述
這裡,我麼看到了一個很奇怪的問題,當我們啟動事務後,然後進行我們的操作,比如我們設定李四的賬戶有300塊錢(set lisi:money 300)當我們按回車鍵的時候,返回一個QUEUED,是佇列的意思,這是為什麼呢?這就是我們要講的在redis中它會用一個佇列來儲存使用者的事務操作,當你exec提交事務後它會按照順序來執行每一條語句。這裡,值得注意的是,當你啟動事務,每執行一個操作,它並不是真正的執行,而是暫時放在這個佇列中,等待事務的提交。如果在提交事務後執行時中間有一個語句出錯會怎麼樣?

這裡有兩種情況。
1.語句有語法錯誤,它會將所有的事務取消。
這裡寫圖片描述

2: 語法本身沒錯,但適用物件有問題. 比如 zadd 操作list物件,Exec之後,會執行正確的語句,並跳過有不適當的語句.(如果zadd操作list這種事怎麼避免? 這一點,由程式設計師負責)

簡單介紹完redis的事務,接著就是與事務密不可分的鎖了。下面我們來討論redis中的鎖應用。

二、redis中鎖的講解及應用

說到鎖,大家都知道有很多鎖,比如樂觀鎖,悲觀鎖,排它鎖,共享鎖等等。
這裡我們簡單所以下樂觀鎖和悲觀鎖。

樂觀鎖

在關係資料庫管理系統裡,樂觀併發控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種併發控制的方法。它假設多使用者併發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分資料。在提交資料更新之前,每個事務會先檢查在該事務讀取資料後,有沒有其他事務又修改了該資料。如果其他事務有更新的話,正在提交的事務會進行回滾。

悲觀鎖

在關係資料庫管理系統裡,悲觀併發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種併發控制的方法。它可以阻止一個事務以影響其他使用者的方式來修改資料。如果一個事務執行的操作都某行資料應用了鎖,那只有當這個事務把鎖釋放,其他事務才能夠執行與該鎖衝突的操作。
悲觀併發控制主要用於資料爭用激烈的環境,以及發生併發衝突時使用鎖保護資料的成本要低於回滾事務的成本的環境中。

上面對於樂觀鎖和悲觀鎖的介紹如果大家理解困難的話,我們可以這樣通俗簡單的理解,對於樂觀鎖,就像一個人的情緒上很樂觀,就好像你要買車票,你總感覺車票還是會有的,你只要在你支付車票費用的時候 觀察一個是否還有車票,如果有就進行支付,如果沒有就進行回滾之前的操作。對於悲觀鎖,一個處理事情比較悲觀,它很擔心會沒有車票,以最壞的情況討論,所以它買票之前對車票進行全程的 監控,一旦沒有票就回退操作(在真正的事務處理中,它會對事務上鎖,不允許其他程序操作該事物,直到釋放該鎖)。

在redis中,它預設使用的是樂觀鎖。只負責監控key是否被改動。
我們來看兩個例子:

multi
set lisi:money 300
set ticket 1

上面程式碼,我們設定了李四有300塊錢,還有一張機票,李四要買這張機票,假設這時有一個比他速度快,先搶到了這張票(啟動另外一個程序)。

decr ticket

這是如果李四繼續買票會發生什麼情況呢?

decrby lisi:money 200
decr ticket
exec

如果只是單單上面的程式碼,我們會發現ticket變為-1,這是絕對不允許發生的,該怎麼辦呢?這是就要用到redis的樂觀鎖,它使用watch命令監控指定key,如果key被改動了,當我們提交事務後,如果發生異常就會取消當前事務,所以我們只需在上面程式碼中開啟事務前加入watch語句就可以避免上面的問題了。

watch ticket

當然,watch也可以簡單是多個key

watch key1 key2 key3...

也可以通過unwatch命令取消對key的監控

unwatch key..