日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

面试问到 Redis 事务,我脸都绿了。。

發布時間:2025/3/21 数据库 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试问到 Redis 事务,我脸都绿了。。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前幾天有讀者說自己面試被問到Redis的事務,雖然不常用,但是面試竟然被問到,平時自己沒有注意Redis的事務這一塊,面試的時候被問到非常不好受。

雖然,這位讀者面試最后算是過了,但是薪資方面沒有拿到自己理想的薪資。

其實這個也是正常的,一般面試被問到爛大街的,誰還問你啊,專門挑一些不常見的來問你,就是為了壓你的薪資。

所以在這里寫一篇文章對Redis的事務進行詳細的講解,估計對Redis事務從理解到原理深入這一篇就夠了。

以后面試都不用擔心了再被問道Redis的事務了,這一篇主要講解Redis事務原理和實操的演練,理解理論的同時也通過實操來證實理論。

事務介紹

Redis事務是一組命令的集合,將多個命令進行打包,然后這些命令會被順序的添加到隊列中,并且按順序的執行這些命令。

「Redis事務中沒有像Mysql關系型數據庫事務隔離級別的概念,不能保證原子性操作,也沒有像Mysql那樣執行事務失敗會進行回滾操作」

這個與Redis的特點:「快速、高效」有著密切的關聯,「因為一些列回滾操作、像事務隔離級別那這樣加鎖、解鎖,是非常消耗性能的」。所以,Redis中執行事務的流程只需要簡單的下面三個步驟:

  • 開始事務(MULTI)

  • 命令入隊

  • 執行事務(EXEC)、撤銷事務(DISCARD )

  • 在Redis中事務的實現主要是通過如下的命令實現的:

    命令功能描述
    MULTI「事務開始的命令」,執行該命令后,后面執行的對Redis數據類型的「操作命令都會順序的放進隊列中」,等待執行EXEC命令后隊列中的命令才會被執行
    DISCARD「放棄執行隊列中的命令」,你可以理解為Mysql的回滾操作,「并且將當前的狀態從事務狀態改為非事務狀態」
    EXEC執行該命令后「表示順序執行隊列中的命令」,執行完后并將結果顯示在客戶端,「將當前狀態從事務狀態改為非事務狀態」。若是執行該命令之前有key被執行WATCH命令并且又被其它客戶端修改,那么就會放棄執行隊列中的所有命令,在客戶端顯示報錯信息,若是沒有修改就會執行隊列中的所有命令。
    WATCH key表示指定監視某個key,「該命令只能在MULTI命令之前執行」,如果監視的key被其他客戶端修改,「EXEC將會放棄執行隊列中的所有命令」
    UNWATCH「取消監視之前通過WATCH 命令監視的key」,通過執行EXEC 、DISCARD 兩個命令之前監視的key也會被取消監視

    以上就是一個Redis事務的執行過程包含的命令,下面就來詳細的圍繞著這幾個命令進行講解。

    開始事務

    MULTI?命令表示事務的開始,當看到OK表示已經進入事務的狀態:

    該命令執行后客戶端會將「當前的狀態從非事務狀態修改為事務狀態」,這一狀態的切換是將客戶端的flags屬性中打開REDIS_MULTI來完成的,該命令可以理解關系型數據庫Mysql的BEGIN TRANCATION語句:

    命令入隊

    執行完MULTI命令后,后面執行的操作Redis五種類型的命令都會按順序的進入命令隊列中,該部分也是真正的業務邏輯的部分。

    Redis客戶端的命令執行后若是當前狀態處于事務狀態命令就會進入隊列中,并且返回QUEUED字符串,表示該命令已經進入了命令隊列中,并且「事務隊列是以先進先出(FIFO)的方式保存入隊的命令」的。

    若是當前狀態是非事務狀態就會立即執行命令,并將結果返回客戶端。在事務狀態「執行操作事務的命令就會被立即執行」,如EXEC、DISCARD、UNWATCH。

    結合上面的分析,Redis執行命令的流程如下圖所示:

    事務的命令隊列中有三個參數分別是:「要執行的命令」「命令的參數」「參數的個數」。例如:通過執行如下的命令:

    redis>?MULTI OK redis>?SET?name?"黎杜" QUEUED redis>?GET?name QUEUED

    那么對應上面的隊列中三個參數如下表格所示:

    執行的命令命令的參數參數的個數
    SET["name", "黎杜"]2
    GET["name"]1

    執行事務

    當客戶端執行EXEC命令的時候,上面的命令隊列就會被按照先進先出的順序被執行,當然執行的結果有成功有失敗,這個后面分析。

    上面說到當客戶端處于非事務的狀態命令發送到服務端會被立即執行,若是客戶端處于事務狀態命令就會被放進命令隊列。

    命令入隊的時候,會按照順序進入隊列,隊列以先進先出的特點來執行隊列中的命令。

    若是客戶端處于事務狀態,執行的是EXEC、DISCARD、UNWATCH這些操作事務的命令,也會被立即執行。

    正常執行

    還是上面的例子,執行如下的代碼:

    redis>?MULTI OK redis>?SET?name?"黎杜" QUEUED redis>?GET?name QUEUED

    所有的命令進入了隊列,當最后執行EXEC,首先會執行SET命令,然后執行GET命令,并且執行后的結果也會進入一個隊列中保存,最后返回給客戶端:

    回復的類型回復的內容
    status code replyOK
    bulk reply"黎杜"

    所以最后你會在客戶端看到「OK、黎杜」,這樣的結果顯示,這個也就是一個事務成功執行的過程。

    至此一個事務就完整的執行完成,并且此時客戶端也從事務狀態更改為非事務狀態。

    放棄事務

    當然你也可以放棄執行該事務,只要你再次執行DISCARD操作就會放棄執行此次的事務。具體代碼如下所示:

    redis>?MULTI OK redis>?SET?name?"黎杜" QUEUED redis>?GET?name QUEUED redis>?DISCARD????//?放棄執行事務 OK

    DISCARD命令取消一個事務的時候,就會將命令隊列清空,并且將客戶端的狀態從事務狀態修改為非事務的狀態。

    「Redis的事務是不可重復的」,當客戶端處于事務狀態的時候,再次向服務端發送MULTI命令時,直接就會向客戶端返回錯誤。

    WATCH 命令

    WATCH命令是在MULTI命令之前執行的,表示監視任意數量的key,與它對應的命令就是UNWATCH命令,取消監視的key。

    WATCH命令有點「類似于樂觀鎖機制」,在事務執行的時候,若是被監視的任意一個key被更改,則隊列中的命令不會被執行,直接向客戶端返回(nil)表示事務執行失敗。

    下面我們來演示一下WATCH命令的操作流程,具體實現代碼如下:

    redis>?WATCH?num OK redis>?MULTI OK redis>?incrby?num?10 QUEUED redis>?decrby?num?1 QUEUED redis>?EXEC???//?執行成功

    這個是WATCH命令的正常的操作流程,若是在其它的客戶端,修改了被監視的任意key,就會放棄執行該事務,如下圖所示:

    客戶端一客戶端二
    WATCH num?
    MULTI?
    incrby num 10get num
    ?decrby num 1
    EXEC?
    執行失敗,返回(nil)?

    WATCH命令的底層實現中保存了watched_keys?字典,「字典的鍵保存的是監視的key,值是一個鏈表,鏈表中的每個節點值保存的是監視該key的客戶端」

    若是某個客戶端不再監視某個key,該客戶端就會從鏈表中脫離。如client3,通過執行UNWATCH命令,不再監視key1:

    錯誤處理

    上面說到Redis是沒有回滾機制的,那么執行的過程,若是不小心敲錯命令,Redis的命令發送到服務端沒有被立即執行,所以是暫時發現不到該錯誤。

    那么在Redis中的錯誤處理主要分為兩類:「語法錯誤」「運行錯誤」。下面主要來講解一下這兩類錯誤的區別。

    語法錯誤

    比如執行命令的時候,命令的不存在或者錯誤的敲錯命令、參數的個數不對等都會導致語法錯誤。

    下面來演示一下,執行下面的四個命令,前后的兩個命令是正確的,中間的兩個命令是錯誤的,如下所示:

    127.0.0.1:6379>?multi OK 127.0.0.1:6379>?set?num?1 QUEUED 127.0.0.1:6379>?set?num (error)?ERR?wrong?number?of?arguments?for?'set'?command 127.0.0.1:6379>?ssset?num?3 (error)?ERR?unknown?command?'ssset' 127.0.0.1:6379>?set?num?2 QUEUED 127.0.0.1:6379>?exec (error)?EXECABORT?Transaction?discarded?because?of?previous?errors.

    語法錯誤是在Redis語法檢測的時候就能發現的,所以當你執行錯誤命令的時候,也會即使的返回錯誤的提示。

    最后,即使命令進入隊列,只要存在語法錯誤,該隊列中的命令都不會被執行,會直接向客戶端返回事務執行失敗的提示。

    運行錯誤

    執行時使用不同類型的操作命令操作不同數據類型就會出現運行時錯誤,這種錯誤時Redis在不執行命令的情況下,是無法發現的。

    127.0.0.1:6379>?multi OK 127.0.0.1:6379>?set?num?3 QUEUED 127.0.0.1:6379>?sadd?num?4 QUEUED 127.0.0.1:6379>?set?num?6 QUEUED 127.0.0.1:6379>?exec 1)?OK 2)?(error)?WRONGTYPE?Operation?against?a?key?holding?the?wrong?kind?of?value 3)?OK 127.0.0.1:6379>?get?key "6"

    這樣就會導致,正確的命令被執行,而錯誤的命令不會不執行,這也顯示出Redis的事務并不能保證數據的一致性,因為中間出現了錯誤,有些語句還是被執行了。

    這樣的結果只能程序員自己根據之前執行的命令,自己一步一步正確的回退,所謂自己的爛攤子,自己收拾。

    Redis事務與Mysql事務

    我們知道關系性數據庫Mysql中具有事務的四大特性:「原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)」

    但是Redis的事務為了保證Redis除了客戶端的請求高效,去除了傳統關系型數據庫的「事務回滾、加鎖、解鎖」這些消耗性能的操作,Redis的事務實現簡單。

    原子性中Redis的事務只能保證單個命令的原子性,多個命令就無法保證,如上面索道的運行時錯誤,即使中間有運行時錯誤出現也會正確的執行后面正確的命令,不具有回滾操作。

    既然沒有了原子性,數據的一致性也就無法保證,這些都需要程序員自己手動去實現。

    Reids在進行事務的時候,不會被中斷知道事務的運行結束,也具有一定的隔離性,并且Redis也能持久化數據。

    總結

    以上是生活随笔為你收集整理的面试问到 Redis 事务,我脸都绿了。。的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。