Redis數據庫高級實用特性:事務控制

 redis對事務的支持目前還比較簡單。redis只能保證一個client發起的事務中的命令能夠連續的執行,而中間不會插入其餘client的命令。 因爲redis是單線程來處理全部client的請求的因此作到這點是很容易的。通常狀況下redis在接受到一個client發來的命令後會當即處理並 返回處理結果,可是當一個client在一個鏈接中發出multi命令有,這個鏈接會進入一個事務上下文,該鏈接後續的命令並非當即執行,而是先放到一個隊列中。當今後鏈接受到exec命令後,redis會順序的執行隊列中的全部命令。並將全部命令的運行結果打包到一塊兒返回給client.而後此鏈接就 結束事務上下文。java

  一、簡單事務控制redis

  下面能夠看一個例子:數據庫

redis 127.0.0.1:6379> get age
"33"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set age 10
QUEUED
redis 127.0.0.1:6379> set age 20
QUEUED
redis 127.0.0.1:6379> exec
1) OK
2) OK
redis 127.0.0.1:6379> get age
"20"
redis 127.0.0.1:6379>

從這個例子咱們能夠看到2個set age命令發出後並沒執行而是被放到了隊列中。調用exec後2個命令才被連續的執行,最後返回的是兩條命令執行後的結果。session

  二、如何取消一個事務spa

  咱們能夠調用discard命令來取消一個事務,讓事務回滾。接着上面例子:線程

redis 127.0.0.1:6379> get age
"20"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set age 30
QUEUED
redis 127.0.0.1:6379> set age 40
QUEUED
redis 127.0.0.1:6379> discard
OK
redis 127.0.0.1:6379> get age
"20"
redis 127.0.0.1:6379>

能夠發現此次2個set age命令都沒被執行。discard命令其實就是清空事務的命令隊列並退出事務上下文,也就是咱們常說的事務回滾。code

  三、樂觀鎖復瑣事務控制orm

  在本小節開始前,咱們有必要向讀者朋友簡單介紹一下樂觀鎖的概念,並舉例說明樂觀鎖是怎麼工做的。隊列

  樂觀鎖:大多數是基於數據版本(version)的記錄機制實現的。何謂數據版本?即爲數據增長一個版本標識,在基於數據庫表的版本解決方案中,通常是經過爲數據庫表添加一個 「version」字段來實現讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加1。事務

  此時,將提交數據的版本號與數據庫表對應記錄的當前版本號進行比對,若是提交的數據版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據。

  樂觀鎖實例:假設數據庫中賬戶信息表中有一個version字段,當前值爲1;而當前賬戶餘額字段(balance)爲$100。下面咱們將用時序表的方式來爲你們演示樂觀鎖的實現原理:

 這樣,就避免了操做員B用基於version=1的舊數據修改的結果來覆蓋操做員A的操做結果的可能。

 即然樂觀鎖比悲觀鎖要好不少,redis是否也支持呢?答案是支持, redis從2.1.0開始就支持樂觀鎖了,能夠顯式的使用watch對某個key進行加鎖,避免悲觀鎖帶來的一系列問題。


Redis樂觀鎖實例:

  假設有一個age的key,咱們開2個session來對age進行賦值操做,咱們來看一下結果如何。

 從以上實例能夠看到在

  第一步,Session 1 尚未來得及對age的值進行修改

  第二步,Session 2 已經將age的值設爲30

  第三步,Session 1 但願將age的值設爲20,但結果一執行返回是nil,說明執行失敗,以後咱們再取一下age的值是30,這是因爲Session 1中對age加了樂觀鎖致使的。

  watch命令會監視給定的key,當exec時候若是監視的key從調用watch後發生過變化,則整個事務會失敗。也能夠調用watch屢次監視多個key.這 樣就能夠對指定的key加樂觀鎖了。注意watch的key是對整個鏈接有效的,事務也同樣。若是鏈接斷開,監視和事務都會被自動清除。固然了exec,discard,unwatch命令都會清除鏈接中的全部監視。

  redis的事務實現是如此簡單,固然會存在一些問題。第一個問題是redis只能保證事務的每一個命令連續執行,可是若是事務中的一個命令失敗了,並不回滾其餘命令,好比使用的命令類型不匹配。下面將以一個實例的例子來講明這個問題:

redis 127.0.0.1:6379> get age
"30"
redis 127.0.0.1:6379> get name
"HongWan"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> incr age
QUEUED
redis 127.0.0.1:6379> incr name
QUEUED
redis 127.0.0.1:6379> exec
1) (integer) 31
2) (error) ERR value is not an integer or out of range
redis 127.0.0.1:6379> get age
"31"
redis 127.0.0.1:6379> get name
"HongWan"
redis 127.0.0.1:6379>

從這個例子中能夠看到,age因爲是個數字,那麼它能夠有自增運算,可是name是個字符串,沒法對其進行自增運算,因此會報錯,若是按傳統關係型數據庫的思路來說,整個事務都會回滾,可是咱們看到redis倒是將能夠執行的命令提交了,因此這個現象對於習慣於關係型數據庫操做的朋友來講是很彆扭的,這一點也是redis今天須要改進的地方。

相關文章
相關標籤/搜索