從示例揭開非關係型資料庫Redis事務管理的面紗
Redis也提供事務這樣的概念,但是相對於關係型資料庫而言,Redis目前對事務提供的是比較簡單的,Redis只能保證一個Client發起的事務命令可以連續的執行,而中間不會插入其他的Client命令,在一個Redis事務中,Redis會將所有的命令放到一個佇列中,當執行執行命令的時候Redis才會批量的處理,要麼都成功,要麼都失敗,這樣就保證了 Redis 事務的原子性。
一、Redis開啟事務示例,關鍵字為multi和exec:
先來對Redis的事務進行一個操作,對其有個直觀的感受。
如上圖,我們先獲取了db這樣一個String型別的值,然後使用multi命令開啟一個事務,我們先將db修改為mongodb,然後修改為redis,QUEUED表示此時命令被順序的放到了一個隊列當中並沒有執行,而當我們執行exec命令的時候,事務才真的提交,並且兩條命令都被執行,最後返回了redis這樣的資訊。
二、Redis取消事務示例,關鍵字為discard:
Redis能夠保證在一個事務中的所有操作按照順序執行,假如在此過程中想要取消這個事務的操作,應該如何處理呢?請看下面的示例,您將會比較清楚的瞭解到類似於事務回滾的功能。
先建立了一個事務,然後修改了db,最後發現不想對其進行修改,因此使用了discard命令,事務被清空了,此時執行exec命令將會報錯。並且我們再次執行get db命令則返回沒有修改前的鍵值。
三、與Redis事務相關的關鍵字watch
在Redis中還有一個事務的實現方式,類似於SVN的操作,使用了資料版本的概念,假設有A,B兩個客戶端,在擁有資料的時候同時擁有一個數據版本,當提交到服務端的時候,如果資料版本大於等於服務端的版本則表明此時資料是有效資料,也就是在此期間沒有發生過其他的變化,如果資料版本小於服務端版本的時候則表明此時資料在此期間被篡改過,因此就會出現衝突,表明該資料已經失效了。
我們來做一個示範,開啟兩個 Redis 的客戶端。
在執行A客戶端exec命令之前,我執行了B客戶端的set命令,然後再才執行的A客戶端的exec命令,此時出現了nil的結果,表面db設定不成功,原因就是使用了Watch命令獲得了db當前的一個數據版本,但是在事務執行的過程中B客戶端已經給伺服器提交了新的資料,也就是說此時服務端資料版本已經要比A客戶端Watch時候新,因此提交的時候就會出現過期。
四、關於語義錯誤造成Redis事務的失敗
在關係型資料庫中,一個事務保證了事務上下文中所有操作的原子性,通俗一點講就是要麼都成功,要麼都失敗,我們已經嘗試了在Redis中命令都成功的情況,事務的確能夠保證原子性的操作,那麼在有錯誤的時候呢?錯誤有兩種型別,第一是語法錯誤,也就是說在事務上下文中,命令的格式書寫出現了問題,第二是語義錯誤,也就是說語法沒有問題,命令的邏輯出現了問題。
語法錯誤:
通過上面的演示,我們發現,事務並沒有提交成功,出現了錯誤的情況,也就是說在一個事務中,當語法出現錯誤的時候就會導致事務上下文的失敗,這很好的體現了事務的原子性。
語義錯誤:
從上圖演示結果表明在事務的上下文中,並沒有保證原子性,所以在編寫程式的時候一定要注意,儘量避免語義錯誤,其實我們在編寫關係型資料庫的SQL或者PLSQL的時候語義錯誤也是百年難得一見,程式程式碼務必保證足夠強大的容錯性。