NoSql-Redis事務

阿翔同學發表於2020-09-28

前面介紹了 Redis的 基本操作 現在來介紹一些面試 比較容易問道的 東西

Redis事務的本質:說白了就是,一組命令的集合! 一個事務中的所有命令都會被序列化,在事務執行過程中按照順序執行

特點:

  1. 一次性
  2. 順序性
  3. 排他性

執行一些列的命令 :------ 佇列 set set set 執行------

  • Redis事務沒有隔離級別的概念!
  • 所有的命令在事務中,並沒有直接被執行【和函式類似,你寫了定義,沒有呼叫同樣的道理】,只有發起執行命令的時候才會被執行! Exec
  • 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。

  • 事務是一個原子操作:事務中的命令要麼全部被執行,要麼全部都不執行。

EXEC 命令負責觸發並執行事務中的所有命令:【類似與回撥函式機制】

當使用 AOF 方式【後面講解】做持久化的時候, Redis 會使用單個 write(2) 命令將事務寫入到磁碟中。

然而,如果 Redis 伺服器因為某些原因被管理員殺死,或者遇上某種硬體故障,那麼可能只有部分事務命令會被成功寫入到磁碟中。如果 Redis 在重新啟動時發現 AOF 檔案出了這樣的問題,那麼它會退出,並彙報一個錯誤。使用redis-check-aof程式可以修復這一問題:它會移除 AOF 檔案中不完整事務的資訊,確保伺服器可以順利啟動。

為什麼 Redis 不支援回滾(roll back)

如果你有使用關係式資料庫的經驗, 那麼 “Redis 在事務失敗時不進行回滾【Orcal有回滾:回bai滾指的是程式或資料du處理錯誤,將程式或資料恢復到上一次正確狀態的行為。回滾包括程式回滾資料回滾等型別。說白了就是類似撤消操作】,而是繼續執行餘下的命令”這種做法可能會讓你覺得有點奇怪。

以下是這種做法的優點:

  • Redis 命令只會因為錯誤的語法而失敗(並且這些問題不能在入隊時發現),或是命令用在了錯誤型別的鍵上面:這也就是說,從實用性的角度來說,失敗的命令是由程式設計錯誤造成的,而這些錯誤應該在開發的過程中被發現而不應該出現在生產環境中。
  • 因為不需要對回滾進行支援,所以 Redis 的內部可以保持簡單且快速。

有種觀點認為 Redis 處理事務的做法會產生 bug , 然而需要注意的是, 在通常情況下, 回滾並不能解決程式設計錯誤帶來的問題。 舉個例子, 如果你本來想通過 INCR 命令將鍵的值加上 1 , 卻不小心加上了 2 , 又或者對錯誤型別的鍵執行了 INCR , 回滾是沒有辦法處理這些情況的。

Redis的事務:

  • 開啟事務(multi)
  • 命令入隊(.......)
  • 執行事務(exec)

----------------------------------------------------------------------------------------------------------------------------- 

  • 127.0.0.1:6379> MULTI                     // 正常執行事務
  • OK
  • 127.0.0.1:6379> set k1 v1
  • QUEUED
  • 127.0.0.1:6379> set k2 v2
  • QUEUED
  • 127.0.0.1:6379> set k3 v3
  • QUEUED
  • 127.0.0.1:6379> GET k2
  • QUEUED
  • 127.0.0.1:6379> exec
  • 1) OK
  • 2) OK
  • 3) OK
  • 4) "v2"

----------------------------------------------------------------------------------------------------------------------------- 

# 放棄事務   事務中的所有命令都不會執行

  • 127.0.0.1:6379> MULTI
  • OK
  • 127.0.0.1:6379> set k1 v1
  • QUEUED
  • 127.0.0.1:6379> set k2 v2
  • QUEUED
  • 127.0.0.1:6379> set k3 v3
  • QUEUED
  • 127.0.0.1:6379> DISCARD 
  • OK
  • 127.0.0.1:6379> get k3
  • (nil)
  • 127.0.0.1:6379> get k2
  • (nil)
  • 127.0.0.1:6379> get k1
  • (nil)

----------------------------------------------------------------------------------------------------------------------------- 

# 編譯型異常(程式碼有問題,命令有錯誤!),事務中的所有命令都不會執行

  • 127.0.0.1:6379> MULTI
  • OK
  • 127.0.0.1:6379> set k1 v1
  • QUEUED
  • 127.0.0.1:6379> set k2 v2
  • QUEUED
  • 127.0.0.1:6379> set k3 v3
  • QUEUED
  • 127.0.0.1:6379> GETSET k2 v4
  • QUEUED
  • 127.0.0.1:6379> GETSET k2
  • (error) ERR wrong number of arguments for 'getset' command
  • 127.0.0.1:6379> 
  • 127.0.0.1:6379> get k3
  • QUEUED
  • 127.0.0.1:6379> EXEC
  • (error) EXECABORT Transaction discarded because of previous errors.
  • 127.0.0.1:6379> 
  • 127.0.0.1:6379> get k1
  • (nil)

----------------------------------------------------------------------------------------------------------------------------- 

執行時異常(1/0), 如果事務佇列中存在語法性,那麼執行命令的時候,其他命令是可以正常執行
的,錯誤命令丟擲異常! 【執行時出錯,有錯的報出異常,沒錯的正常執行】
  • 127.0.0.1:6379> MULTI
  • OK
  • 127.0.0.1:6379> set k1 "libero"
  • QUEUED
  • 127.0.0.1:6379> set k2 v2 
  • QUEUED
  • 127.0.0.1:6379> set k3  v3
  • QUEUED
  • 127.0.0.1:6379> INCRBY k1  5    //  字串  + - 出錯
  • QUEUED
  • 127.0.0.1:6379> GET k1
  • QUEUED
  • 127.0.0.1:6379> GET k2
  • QUEUED
  • 127.0.0.1:6379> exec
  • 1) OK
  • 2) OK
  • 3) OK
  • 4) (error) ERR value is not an integer or out of range
  • 5) "libero"
  • 6) "v2"

----------------------------------------------------------------------------------------------------------------------------- 

監控! watch(面試常問)

不會吧 不會吧  Redis 也有Sql的 悲觀鎖  樂觀鎖 ?是的 錯了 這裡只是用 watch達到樂觀鎖的目的

先來介紹一下 悲觀,樂觀鎖

悲觀鎖:很悲觀,認為什麼時候都會出問題,無論做什麼都會加鎖!【顧名思義】雖說保證了安全性但是效率很低,傳統的關係型資料庫 有很多這樣的列子:比如 行鎖,表鎖,讀鎖,寫鎖等,都是在操作前加上鎖,防止多人修改同一條資料。這樣的話就成功提高了資料的一致性,降低了併發性。

樂觀鎖:  很樂觀,認為什麼時候都不會出現問題,所以不會上鎖!更新資料的時候取判斷一下,在此期間是否有人修改過

這個資料。通過獲取version,更新的時候比較version【通過watch達到目的】樂觀鎖策略:提交版本必須大於記錄當前版本才能更新資料

這裡就是 另一個 client 修改了 當前的 版本,處理事務這個client的版本就是watch的時候獲取的版本,但之後在執行Exec之前,我們用另一個client修改了當前的版本 ,讓money這個version > 處理事務的client。所以按照執行策略,這裡的事務執行是失敗的。

  • 27.0.0.1:6379> set money 100
  • OK
  • 127.0.0.1:6379> set out 0
  • OK
  • 127.0.0.1:6379> WATCH money
  • OK
  • 127.0.0.1:6379> MULTI
  • OK
  • 127.0.0.1:6379> INCRBY money -20
  • QUEUED
  • 127.0.0.1:6379> INCRBY out 20
  • QUEUED
  • 127.0.0.1:6379> exec      // 如果發現事務執行失敗
  • (nil)
  • 127.0.0.1:6379> UNWATCH    // 先解鎖
  • OK
  • 127.0.0.1:6379> WATCH money   // 在重新獲取版本
  • OK 
  • 127.0.0.1:6379> multi
  • OK
  • 127.0.0.1:6379> INCRBY money -20
  • QUEUED
  • 127.0.0.1:6379> INCRBY out 20
  • QUEUED
  • 127.0.0.1:6379> exec
  • 1) (integer) 180
  • 2) (integer) 20​​​​​​​

 

 

 

 

 

 

 

 

 

 

 

相關文章