Redis之Redis的事務

1.Redis的事務是什麼

Redis 事務的本質是一組命令的集合,事務支持一次執行多個命令,一個事務中全部命令都會被序列化(redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令).redis

1.1reids事務的特色

1. 事務同命令同樣都是Redis最小的執行單位,一個事務中的命令要麼都執行,要麼都不執行數據庫

2.在事務執行過程,會按照順序串行化執行隊列中的命令,其餘客戶端提交的命令請求不會插入到事務執行命令序列中編程

3.Redis的事務還能保證一個事務內的命令依次執行而不被其餘命令插入數組

1.2.Redis的經常使用操做

MULTI, EXEC, DISCARD and WATCH 是Redis事務的基礎用來顯式開啓並控制一個事務,它們容許在一個步驟中執行一組命令。並提供兩個重要的保證:bash

1. 事務中的全部命令都會被序列化並按順序執行。在執行Redis事務的過程當中,不會出現由另外一個客戶端發出的請求。這保證 命令隊列 做爲一個單獨的原子操做被執行。服務器

2.隊列中的命令要麼所有被處理,要麼所有被忽略。EXEC命令觸發事務中全部命令的執行,所以,當客戶端在事務上下文中失去與服務器的鏈接.ui

1.2.1MULTI 命令

用於標記事務塊的開始。Redis會將後續的命令逐個放入隊列中,而後才能使用EXEC命令原子化地執行這個命令序列。這個命令的運行格式以下所示:MULTIspa

這個命令的返回值是一個簡單的字符串,老是OK。設計

1.2.2. EXEC命令

在一個事務中執行全部先前放入隊列的命令,而後恢復正常的鏈接狀態。當使用WATCH命令時,只有當受監控的鍵沒有被修改時,EXEC命令纔會執行事務中的命令,這種方式利用了檢查再設置(CAS)的機制()。這個命令的運行格式以下所示:EXEC3d

這個命令的返回值是一個數組,其中的每一個元素分別是原子化事務中的每一個命令的返回值。當使用WATCH命令時,若是事務執行停止,那麼EXEC命令就會返回一個Null值。(若是在發送EXEC命令前客戶端斷線了,則Redis會清空事務隊列,事務中的全部命令都不會執行。而一旦客戶端發送了EXEC命令,全部的命令就都會被執行)

1.2.3. DISCARD命令

清除全部先前在一個事務中放入隊列的命令,而後恢復正常的鏈接狀態。若是使用了WATCH命令,那麼DISCARD命令就會將當前鏈接監控的全部鍵取消監控。這個命令的運行格式以下所示:DISCARD

這個命令的返回值是一個簡單的字符串,老是OK。

1.2.4. WATCH命令

當某個事務須要按條件執行時,就要使用這個命令將給定的鍵設置爲受監控的.

1.Watch指令,相似樂觀鎖,事務提交時,若是Key的值已被別的客戶端改變,好比某個list已被別的客戶端push/pop過了,整個事務隊列都不會被執行

2.經過WATCH命令在事務執行以前監控了多個Keys,假若在WATCH以後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回Nullmulti-bulk應答以通知調用者事務執行失敗.這個命令的運行格式以下所示:WATCH key [key ...]

這個命令的返回值是一個簡單的字符串,老是OK。對於每一個鍵來講,時間複雜度老是O(1)。

1.2.5. UNWATCH命令

清除全部先前爲一個事務監控的鍵。若是你調用了EXEC或DISCARD命令,那麼就不須要手動調用UNWATCH命令。這個命令的運行格式以下所示:UNWATCH

這個命令的返回值是一個簡單的字符串,老是OK。時間複雜度老是O(1)。

2.Redis 事務的三個階段

Redis 中的事務從開始到結束也是要經歷三個階段:開啓事務,命令入列,執行事務/放棄事務

2.1開啓事務階段

1.multi 命令用於開啓事務

2.multi 命令能夠讓客戶端從非事務模式狀態,變爲事務模式狀態,以下圖所示

3.注意:multi 命令不能嵌套使用,若是已經開啓了事務的狀況下,再執行 multi 命令,會提示以下錯誤:

複製代碼
錯誤:(error) ERR MULTI calls can not be nested
  執行效果,以下代碼所示:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> multi
(error) ERR MULTI calls can not be nested複製代碼
複製代碼

4.當客戶端是非事務狀態時,使用 multi 命令,客戶端會返回結果 OK ,若是客戶端已是事務狀態,再執行 multi 命令會 報不能嵌套的錯誤,但不會終止客戶端爲事務的狀態,以下圖所示

2.2命令入列階段

1.客戶端進入事務狀態以後,將多個命令入隊到事務中,接到這些命令並不會當即執行,而是放到等待執行的事務隊列裏面,命令入列成功後會返回 QUEUED,以下代碼所示:

> multi
OK
> set k v
QUEUED
> get k
QUEUED複製代碼

2.命令會按照先進先出(FIFO)的順序出入列,也就是說事務會按照命令的入列順序,從前日後依次執行。

執行流程以下圖所示:

2.3執行事務/放棄事務階段

執行事務的命令是 exec ,放棄事務的命令是 discard

執行事務示例代碼以下:

複製代碼
> multi
OK
> set k v2
QUEUED
> exec
1) OK
> get k
"v2"複製代碼
複製代碼
複製代碼

放棄事務示例代碼以下:

複製代碼
> multi
OK
> set k v3
QUEUED
> discard
OK
> get k
"v2"複製代碼
複製代碼

3.事務錯誤&回滾

事務執行中的錯誤分爲如下三類:

1.執行時纔會出現的錯誤(簡稱:執行時錯誤)

2.入列時錯誤,不會終止整個事務;

3.入列時錯誤,會終止整個事務。

3.1執行時錯誤

從如下實例結果能夠看出,即便事務隊列中某個命令在執行期間發生了錯誤,事務也會繼續執行,直到事務隊列中全部命令執行完成。

3.2入列時,錯誤不會致使事務結束

從如下實例結果能夠看出,重複執行 multi 會致使入列錯誤,但不會終止事務,最終查詢的結果是事務執行成功了。除了重複執行 multi 命令,還有在事務狀態下執行 watch 也是一樣的效果

3.3入列錯誤會致使事務結束

3.4爲何不支持事務回滾?

不支持事務回滾的緣由有如下兩個:

1.Redis事務的執行時,錯誤一般都是編程錯誤形成的,這種錯誤一般只會出如今開發環境中,而不多會在實際的生產環境中出現,因此他認爲沒有必要爲 Redis 開發事務回滾功能;

2.不支持事務回滾是由於這種複雜的功能和 Redis 追求的簡單高效的設計主旨不符合。

4.Redis事務的三個特性

1.單獨的隔離操做:事務中的全部命令都會序列化、按順序地執行。事務在執行的過程當中,不會被其餘客戶端發送來的命令請求所打斷。

2.沒有隔離級別的概念:隊列中的命令沒有提交以前都不會實際的被執行,由於事務提交前任何指令都不會被實際執行,也就不存在」事務內的查詢要看到事務裏的更新,在事務外查詢不能看到」這個

3.不保證原子性:redis同一個事務中若是有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾

5.悲觀鎖與樂觀鎖

1.悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖

2.樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐;樂觀鎖策略:提交版本必須大於記錄當前版本才能執行更新

相關文章
相關標籤/搜索