Redis核心技術---事務管理
目錄
1.Redis事務基本命令
雖然redis是一種基於記憶體的nosql,但是其也是支援事務的,只不過沒有傳統的關係型資料庫(如MySql)那麼強大,下面給出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 | 執行緒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之間的命令都不會被執行。 |