1. 程式人生 > >Redis核心技術---事務管理

Redis核心技術---事務管理

目錄

1.Redis事務基本命令

2.開啟與執行事務

3.事務回滾

4.多執行緒中的事務


1.Redis事務基本命令


雖然redis是一種基於記憶體的nosql,但是其也是支援事務的,只不過沒有傳統的關係型資料庫(如MySql)那麼強大,下面給出redis的事務命令:

表1-1     Redis事務命令
命令 說明 備註
multi

開啟事務命令,之後的命令就進入佇列,而不會馬上被執行

在事務生存期間,所有的Redis關於資料結構的命令都會入隊
watch key1[key2....] 監聽某些鍵,當被監聽的鍵在事務執行前被修改,則事務會被回滾
unwatch key1[key2...] 取消監聽某些建

exec 執行事務,如果被監聽的鍵沒有被修改,則採用執行命令,否則就回滾命令 在執行事務佇列儲存的命令前,Redis會檢測被監聽的鍵值對有沒有發生變化,如果沒有就執行命令,否則就回滾事務
discard 回滾事務 回滾進入佇列的事務命令,之後就不能再用exec命令提交了。

2.開啟與執行事務


 redis通過multi開啟事務,事務開啟後的所有命令都會放入佇列中等待執行,當遇到exec命令時,將會一次性執行佇列中的所有命令,如下圖測試:

 從上圖可以發現,使用multi命令開啟事務後,接下來的set命令和get命令按回車執行後都會顯示QUEUED,表示該命令已經放入佇列,當執行exec命令的時候,佇列中的所有命令將會一次性全部執行,並返回執行結果,如上圖所示返回OK和“value1”。

3.事務回滾


如表1-1,事務回滾的命令為discard,關於事務回滾這裡有三種情況,分別為

手動執行discard命令進行回滾、遇到命令格式錯誤redis自動進行回滾、遇到操作資料錯誤(如資料格式錯誤)不回滾

1. 在開啟的事務被執行(exec)前,如果執行事務回滾命令(discard),則之前放入佇列中的所有命令將會被清除,此時如果再執行exec會報錯,因為佇列中已經沒有了命令,如下測試結果:

2.在開啟事務後如果執行的命令格式錯誤(注意是格式錯誤),則Redis會自動回滾exec前的所有命令。如下:

如上,在輸入了錯誤的命令ged key1後,執行exec命令會提示:Transaction discarded because of previous errors,表明事務已經被回滾了,此時exec之前的所有命令都不會被執行(注意在Redis2.6.5之前的版本會忽略有語法錯誤的命令,然後執行事務中其他語法正確的命令)

3.那如果命令格式沒有錯,但是執行錯誤(資料格式錯誤或者用操作連結串列型別的命令操作集合型別)呢?Redis會怎麼回滾呢?如下:

如上圖,incr key1命令本身沒有錯,但是由於key1的值是字串而不是整數,不能對其使用incr(自增)運算,所以exec後會報錯,但是讀者會發現出錯的命令之前和之後的命令都被正常執行了,由此可以看出由於資料格式導致的錯誤Redis事務並不會被正確回滾。

那麼到這裡讀者可能會有疑問了,那要怎麼解決呢?答案是解決不了啊哈哈哈哈,redis並不支援回滾執行錯誤的事務,我們必須通過程式去檢測資料的正確性,以保證Redis事務的正確執行,如果萬一事務提交時出現了執行錯誤,那麼我們只好自己收拾剩下的攤子了(即將資料恢復事務執行前的狀態)。

那我們可愛的讀者可能又會有疑問了,為什麼Redis不支援呢?是因為實現不了嗎(怎麼可能哈哈哈哈哈),要知道安全和效能從來都是魚和熊掌的關係,Redis為了保持其效能只能削弱其事務管理的功能啦。

4.多執行緒中的事務


我們之前討論的情況都是在單執行緒的環境中,當存在多執行緒時又是另外一種情況了。

當A執行緒去執行某些業務邏輯,而這些業務邏輯所操作的資料(公共資料)又被B執行緒共享了,B執行緒很有可能會去修改公共資料,而A執行緒並不知道資料被修改了,最終導致的後果就是A執行緒的業務邏輯運算很有可能出錯。

那麼怎麼解決呢?我們可以對公共資料加一個檢測其是否被改變的監聽器,那就是我們表1-1中的watch命令啦。當redis使用exec命令執行事務的時候,他首先會去對比被watch命令所監控的鍵值對,如果沒有發生變化,那麼他會執行事務佇列中的命令,提交事務,如果發生變化,那麼它不會執行任何事務中的命令,而去回滾事務。無論事務是否回滾,redis都會去取消執行事務前的watch命令。

由於多執行緒示例不好實現,我們以表格的形式向讀者舉例說明watch命令的使用:

表1-4   watch命令在多執行緒中的使用
時刻 執行緒1 執行緒2 說明
T1 set key1 value1 ----- 執行緒1:建立了一條共享資料key1
T2 watch key1 ----- 執行緒1:開啟了對共享資料key1的監控
T3 multi ----- 執行緒1:開啟了事務
T4 do something ....... ----- 執行緒1:在事務中執行了一些邏輯操作
T5 ------ set key1 newValue1 執行緒2:修改了公共資料key1的值
T6 exec ----- 執行緒1:執行緒一在提交事務時,會去檢測在T2時刻被監控的公共資料key1是否被修改過,發現key1在T5時刻被執行緒2修改了,所以執行緒1會直接回滾事務,multi到exec之間的命令都不會被執行。