1. 程式人生 > >NoSQL資料庫Redis支援的簡單事務

NoSQL資料庫Redis支援的簡單事務

  Redis作為一個數據庫,也提供了比較簡單的事務操作來保證原子性,首先來對比一下Redis和傳統資料庫Mysql的事務操作:

資料庫 mysql redis
開啟 start transaction multi
語句 sql語句 redis命令
失敗 rollback 回滾 discard 取消
成功 commit 提交 exec 執行

Redis的一個事務從開始到執行會經歷以下三個階段:開始事務 ---》命令入隊 ---》 執行事務。首先看一個正確的Redis事務:

從截圖中可以看出,使用multi開啟事務,實際上是把命令存入一個QUEUE當中,使用exec來執行QUEUE當中的命令,而使用discard會捨棄QUEUE當中的命令。

不過Redis的事務,不像mysql那樣,保證絕對的原子性,要麼都成功,要麼都失敗。因為在使用Redis事務的時候,收到 EXEC 命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然被執行,在事務執行過程,其他客戶端提交的命令請求不會插入到事務執行命令序列中。這樣就保證不了原子性了,也是一個坑呀!下面舉例說明:

1、寫入的redis命令有錯誤

tmd不是Redis中的命令,當執行這個tmd時會報錯,導致QUEUE當中的命令得不到執行,相當於mysql中的回滾,這還好,也相當程式正常運行了!

2、寫入的redis命令沒有錯誤,但是執行的物件有問題

可以看出,雖然QUEUE執行命令當中有一句命令是錯誤的,但是其他的操作還可以正常進行,並沒有回滾或者是取消,有問題吧!這種命令問題怎麼避免的,我想還是我們搬磚者本身提高程式碼質量吧!

3、多執行緒操作Redis的併發問題,春節將至,我們就舉搶票的例子吧!

按照上面數字標註的順序:123來執行,可以看到Redis的事務並沒有提供隔離性,在一個事務exec之前,另外一個事務提前exec了,這就照成了票數將為-1,這肯定不符合實際。

有問題的出現,就要有解決方案的出現。Redis針對沒有隔離性這一說,提供了watch的機制,相當於樂觀鎖一樣,如果一個key被監視,那麼在Redis執行exec命令之前會檢查這個被監視的key有沒有改動過,改過就取消執行。

這次我們對ticket加了watch進行監視,叫“fu”的那個人網速還是比我快,提前把票搶走了,但是我這邊再進行exec提交就沒那麼尷尬了,票數是0沒有變為-1,錢也沒扣我的。

綜上,單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增加任何維持原子性的機制,所以 Redis 事務的執行並不是原子性的。事務可以理解為一個打包的批量執行指令碼,但批量指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做。如果還想保證像關係型資料庫那樣的隔離性(其實不是隔離性,只是一個監視),還要配合watch命令對要操作的key進行一個監視,取消監視就用unwatch命令!