1. 程式人生 > 實用技巧 >C++演算法:圖論基礎

C++演算法:圖論基礎

redis事務

MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事務相關的命令。

事務可以一次執行多個命令, 並且帶有以下兩個重要的保證:

1.事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。

2.事務是一個原子操作:事務中的命令要麼全部被執行,要麼全部都不執行。

EXEC 命令負責觸發並執行事務中的所有命令: 如果客戶端在使用 MULTI 開啟了一個事務之後,卻因為斷線而沒有成功執行 EXEC ,那麼事務中的所有命令都不會被執行。 另一方面,如果客戶端成功在開啟事務之後執行 EXEC ,那麼事務中的所有命令都會被執行。 MULTI 命令用於開啟一個事務,它總是返回 OK 。 MULTI 執行之後, 客戶端可以繼續向伺服器傳送任意多條命令, 這些命令不會立即被執行, 而是被放到一個佇列中, 當 EXEC命令被呼叫時, 所有佇列中的命令才會被執行。 另一方面, 通過呼叫 DISCARD , 客戶端可以清空事務佇列, 並放棄執行事務。 以下是一個事務例子, 它原子地增加了 foo 和 bar 兩個鍵的值:

> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1

放棄事務 當執行 DISCARD 命令時, 事務會被放棄, 事務佇列會被清空, 並且客戶端會從事務狀態中退出:

> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"

事務中的錯誤 使用事務時可能會遇上以下錯誤:

事務在執行 EXEC 之前,入隊的命令可能會出錯。比如說,命令可能會產生語法錯誤(引數數量錯誤,引數名錯誤,等等),或者其他更嚴重的錯誤,比如記憶體不足(如果伺服器使用 maxmemory 設定了最大記憶體限制的話)。 命令可能在 EXEC 呼叫之後失敗。舉個例子,事務中的命令可能處理了錯誤型別的鍵,比如將列表命令用在了字串鍵上面,諸如此類。 對於發生在 EXEC 執行之前的錯誤,客戶端以前的做法是檢查命令入隊所得的返回值:如果命令入隊時返回 QUEUED ,那麼入隊成功;否則,就是入隊失敗。如果有命令在入隊時失敗,那麼大部分客戶端都會停止並取消這個事務。 不過,從 Redis 2.6.5 開始,伺服器會對命令入隊失敗的情況進行記錄,並在客戶端呼叫 EXEC 命令時,拒絕執行並自動放棄這個事務。 在 Redis 2.6.5 以前, Redis 只執行事務中那些入隊成功的命令,而忽略那些入隊失敗的命令。 而新的處理方式則使得在流水線(pipeline)中包含事務變得簡單,因為傳送事務和讀取事務的回覆都只需要和伺服器進行一次通訊。

至於那些在 EXEC 命令執行之後所產生的錯誤, 並沒有對它們進行特別處理: 即使事務中有某個/某些命令在執行時產生了錯誤, 事務中的其他命令仍然會繼續執行。執行時錯誤,提交事務之後,redis會執行其他可執行的命令。語法錯誤,及入佇列時就時錯誤的,那麼這條事務就會被拋棄,再提交時也會報錯所以redis不支援事務回滾。

使用watch命令(CAS原理) WATCH命令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之後的事務就不會執行。監控一直持續到EXEC命令(事務中的命令是在EXEC之後才執行的,所以在MULTI命令後可以修改WATCH監控的鍵值)

  val = GET mykey
  val 
= val + 1 SET mykey $val`

上述的程式碼會出現一個問題,因為上面吧正常的一個incr(原子遞增操作)分為了兩部分,那麼在多執行緒(分散式)環境中,這個操作就有可能不再具有原子性了。 具體做法

 WATCH mykey
 val = GET mykey
 val = val + 1
 MULTI
 SET mykey $val
 EXEC

新程式碼在獲取mykey的值之前先通過WATCH命令監控了該鍵,此後又將set命令包圍在事務中,這樣就可以有效的保證每個連線在執行EXEC之前,如果當前連接獲取的mykey的值被其它連線的客戶端修改,那麼當前連線的EXEC命令將執行失敗。這樣呼叫者在判斷返回值後就可以獲悉val是否被重新設定成功。

注意:

由於WATCH命令的作用只是當被監控的鍵值被修改後阻止之後一個事務的執行,而不能保證其他客戶端不修改這一鍵值,所以在一般的情況下我們需要在EXEC執行失敗後重新執行整個函式。 執行EXEC命令後會取消對所有鍵的監控,如果不想執行事務中的命令也可以使用UNWATCH命令來取消監控。