跟我一塊兒學Redis之Redis事務簡單瞭解一下

前言

關係數據庫中的事務,小夥伴們應該是不陌生了,不論是在開發仍是在面試過程當中,總有兩個問題逃不掉:面試

•說說事務的特性;•事務隔離級別是怎麼一回事?數據庫

事務處理很差,數據就可能不許確,最終就會致使業務出問題;藉此機會簡單回顧一下事務特性及其隔離級別,就當是複習了;編程

事務特性(ACID)

•原子性(Atomicity)指事務內全部操做要麼一塊兒執行成功,要麼都一塊兒失敗(或者說是回滾);如事務經典轉帳案例:A給B轉帳,A把錢扣了,但B沒有收到;可見這種錯誤是不能接受的,最終會回滾,這也是原子性的重要性。•一致性(Consistency)指事務執行先後的狀態一致,如事務經典轉帳案例:A給B互相轉帳,無論怎麼轉,最終二者錢的總和仍是不變;•持久性(Durability)指事務一旦提交,數據就已經永久保存了,不能再回滾;•隔離性(Isolation)指多個併發事務之間的操做互不干擾,可是事務的併發可能會致使數據髒讀、不可重複讀、幻讀問題,根據業務狀況,採用事務隔離級別進行對應數據讀問題處理。服務器

事務隔離級別

•讀未提交(Read uncommitted)指一個事務讀取到其餘未提交事務的數據。可能致使數據髒讀。轉帳案例:A正在給B轉帳,原本轉的1000,A多輸入了個0,變成10000,但此事務還未提交,但此時B查詢到轉入的是10000,但A取消事務回滾以後,B又查詢不到轉入的數據。這種狀況就是髒讀•讀已提交(Read committed)指一個事務只能讀取到其餘事務已提交的數據,從而解決了髒讀的問題。但可能致使數據不可重複讀;轉帳案例:A要給B轉帳1000,A先查看了一下餘額,有1000,而後開始給B轉錢,但此時A家裏電費經過開啓的自動繳費功能,自動從A帳戶扣除200繳納電費,並提交;當A轉帳準備提交,再次確認餘額時,錢少了200。這樣就致使同一個事務中屢次查詢的結果不一致,這種狀況就是不可重複讀;•可重複讀(Repeatable read)指事務只要一開啓,就不容許其餘事務進行修改操做,從而解決了不可重複讀問題。但可能致使數據幻讀;轉帳案例:A常常給B轉帳,到年末了,須要查帳,而後開啓了一個事務進行查詢統計,剛開始查詢只是10條轉帳記錄,正準備統計時,由於緊急狀況A須要給B轉一筆錢應急,從而新增了一條新記錄,並提交;而查帳事務正在統計中,最後發現轉帳額和看到的10條轉帳記錄不匹配。這種狀況就是幻讀•序列化(Serializable )指事務之間只能串行話執行,就像隊列同樣,排隊進行,這樣就解決了幻讀的問題,可是這種級別的併發性能不高,非特殊需求,這種級別通常不用。併發

正文

轉入正題,結合關係型數據庫的事務來看看Redis中事務有什麼不一樣;性能

Redis事務是指將多條命令加入隊列,一次批量執行多條命令,每條命令會按順序執行,事務執行過程當中不會受客戶端傳入的命令請求影響。學習

Redis事務的相關命令以下:spa

•MULTI:標識一個事務的開啓,即開啓事務;•EXEC:執行事務中的全部命令,即提交;•DISCARD:放棄事務;和回滾不同,Redis事務不支持回滾。•WATCH:監視Key改變,用於實現樂觀鎖。若是監視的Key的值改變,事務最終會執行失敗。•UNWATCH:放棄監視。隊列

Redis事務和關係型數據庫的事務不太同樣,它不保證原子性,也沒有隔離級別的概念。來,結合命令演示,實戰說明一切:事務

沒有隔離級別

image-20201112153132140

如上圖所示,當事務開啓時,事務期間的命令並無執行,而是加入隊列,只有執行EXEC命令時,事務中的命令纔會按照順序一一執行,從而事務間就不會致使數據髒讀、不可重複讀、幻讀的問題,所以就沒有隔離級別

不保證原子性

image-20201112154524168

如上圖所示,在經過EXEC執行事務時,其中命令執行失敗不會影響到其餘命令的執行,並無保證同時成功和同時失敗的原子操做,儘管這樣,Redis事務中也沒有提供回滾的支持,官方提供了兩個理由:

image-20201112160255544

大概的意思就是:

•使用Redis命令語法錯誤,或是將命令運用在錯誤的數據類型鍵上(如對字符串進行加減乘除等),從而致使業務數據有問題,這種狀況認爲是編程致使的錯誤,應該在開發過程當中解決,避免在生產環境中發生;•因爲不用支持回滾功能,Redis內部簡單化,並且還比較快;

在事務命令入隊過程當中,發現相關命令邏輯使用錯誤,能夠進行放棄該事務;若是使用錯誤的Redis命令,且沒有放棄事務,最終也會致使事務總體執行失敗,這也算是爲原子性扳回一局,以下:

放棄事務

image-20201112223050653

命令語法錯誤致使事務執行失敗

image-20201112223821761

使用WATCH實現樂觀鎖

說到樂觀鎖,就和悲觀鎖一塊兒簡單說說對其的理解:

樂觀鎖:就是很是樂觀,作什麼事都往好處想;對於數據庫操做,就認爲每次操做數據的時候都認爲別的操做不會修改,因此不會加鎖,而是經過一個相似於版本的字段來標識該數據是否修改過,在執行本次操做前先判斷是否修改過,若是修改過就放棄本次操做從新再來;

悲觀鎖:就是很是悲觀,作什麼事都以爲很差;對於數據庫操做,每次操做數據數據都會認爲別的操做會修改當前數據,因此都要對其進行加鎖,相似於表鎖和行鎖。

WATCH經過監視指定Redis Key,若是沒有改變,就執行成功,若是發現對應值發生改變,事務就會執行失敗,以下圖;

image-20201112232612965

那會一直監視指定的Key嗎?,答案固然是不會的,如下三種方式能夠取消監視:

•事務執行以後,不論是否執行成功還好是失敗,都會取消對應的監視;•當監視的客戶端斷開鏈接時,也會取消監視;•能夠手動UNWATCH取消全部Key的監視;

Redis事務優缺點

優勢

•一次性按順序執行多個Redis命令,不受其餘客戶端命令請求影響;•事務中的命令要麼都執行(命令間執行失敗互相不影響),要麼都不執行(好比中間有命令語法錯誤);

缺點

•事務執行時,不能保證原子性;•命令入隊每次都須要和服務器進行交互,增長帶寬;

注意

•當事務中命令語法使用錯誤時,最終會致使事務執行不成功,即事務內全部命令都不執行;•當事務中命令知識邏輯錯誤,就好比給字符串作加減乘除操做時,只能在執行過程當中發現錯誤,這種事務執行中失敗的命令不影響其餘命令的執行。

總結

對於Redis事務,其實用的不是不少,大部分喜歡使用Lua腳本進行批量命令的執行,同時還能保證命令執行的原子性。

那爲何要說Redis事務呢?

在以前計劃寫這篇文章的時候,和一些朋友簡單溝經過,你們的確用的很少,基本上都是用Lua腳本;但面試會時不時遇到過Redis事務的問題,最多見的是Redis中的事務和關係型數據庫中的事務有什麼區別,這是從面試角度出發有這篇文章;

其實Redis 2.6版本以前,還不支持Lua腳本時,Redis事務對於批量按序執行命令的場景也是很用的;就拿當下來講,若是一些業務需批量按序執行命令的,一樣可使用,並不是必定要Lua腳本。這是從使用角度來講;

最後從學習角度來講,既然學Redis,就應該儘量的瞭解的多一點。下一篇說說持久化。

一個被程序搞醜的帥小夥,關注"Code綜藝圈",跟我一塊兒學~ 

相關文章
相關標籤/搜索