理解原子性
我們知道,java中的 i++ 或者 ++i 這些自增操作不具備原子性,因為自增操作在我們代碼層面是一個指令,但是在 jvm 底層,它分為這兩個步驟:
- 從區域變數表中讀取 i 的值壓入運算元堆疊
- 將區域變數表中 i 的值加1
若 jvm 在執行第 1 步的時候,其他執行緒先于這個執行緒改變了 i 的值,然后執行第二步后得出的值就不是我們希望的,
在 redis 中也有類似的自增操作,如我們之前學的 string 資料型別中的 incr 指令,它可以對一個 integer 型別的值加1,但是 incr 指令與 java 自增不一樣的是,它是一個原子操作,因為 incr 是呼叫作業系統底層的指令,它不會被其他執行緒打斷,所以 incr 指令具有原子性,
為什么叫原子性?
原子性其實就是有類似原子的性質,我們知道原子中有質子和中子,他們構成了原子,不可分割,如果分割了,就不是一個原子了,是不是很好理解,整理redis的同時也整理了最近兩個月最新的面試題,需要的朋友可以點擊:這個,點這個!!,備注:csdn,

什么是事務
事務就是指一系列操作,這些操作要么同時成功,要么同時失敗,它是一種原子操作,原子就是一個整體,不可分割,事務中的這些操作也是一樣,
假設有這樣一個場景:張三向李四轉賬 100 塊錢,最少需要經歷兩個步驟
- 張三的銀行卡中錢減100塊
- 李四的銀行卡中錢加100塊
在沒有事務的情況下,可能會導致 1 號操作執行成功,2 號操作執行失敗,那結果是張三的錢少了 100 塊,李四的錢卻沒增加,張三的 100 塊憑空消失了,這肯定會出問題,所以這兩部操作必須要放在事務中執行,要么轉賬成功,要么轉賬失敗,這就是事務的作用,
redis事務
redis 是單執行緒的程式,每個指令都保證原子性,但是不保證多個指令的原子性,
當有多個客戶端連接同一個 redis 時,客戶端之間會競爭cpu資源,來爭奪 rdis 指令的執行權,所以如果一個 client 要執行一系列指令時,可能會被其他客戶端打斷,
要使多個指令也具有原子性,可以使用 redis 事務
redis 事務保證兩點:
- 執行一個事務時,所有的命令都會被順序執行,且不會被其他客戶端打斷
- 執行一個事務時,所有命令要么同時成功,要么同時失敗
如果 redis 開啟 AOF 模式,在執行 redis 事務之前,redis 會先把事務寫在磁盤中再執行命令,如果事務執行到一半,redis 行程突然就掛了,那么就會導致事務中只有一部分指令執行成功,還有一部分指令還未執行,這種情況下,在 redis 下一次啟動時會檢測到錯誤,并退出 redis,使用 redis-check-aof 工具可以對 AOF 檔案進行修復,洗掉掉磁盤中的未執行成功的事務,然后重新啟動加載 AOF 檔案,redis 就恢復到事務沒有執行創建的狀態,就可以正常啟動了
事務相關的命令
和 redis 事務有關的指令有:
- multi
- exec
- discard
下面開始介紹每個命令
multi
使用 multi 指令來開啟事務
127.0.0.1:6379> set zhangsan 1000
OK
127.0.0.1:6379> set lisi 1000
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby zhangsan -100
QUEUED
127.0.0.1:6379> incrby lisi 100
QUEUED
multi 指令回傳 ok,證明事務開啟成功,
開啟事務后,接下來執行每條正確的指令都回傳 QUEUE,代表命令被放入等待佇列,但并沒有執行,
exec
使用 exec 命令來執行事務
127.0.0.1:6379> set zhangsan 1000
OK
127.0.0.1:6379> set lisi 1000
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby zhangsan -100
QUEUED
127.0.0.1:6379> incrby lisi 100
QUEUED
127.0.0.1:6379> exec # 執行事務
1) (integer) 900
2) (integer) 1100
使用 exec 執行事務后,會按順序回傳事務中每天指令的回傳結果,
還整理了Java核心的知識點,大家也可以看看,需要的朋友可以點擊:這個,點這個!!,備注:csdn,

discard
如果事務創建成功,但你又不想執行了,使用 discard 命令來取消
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379> incrby zhangsan -100
QUEUED
127.0.0.1:6379> incrby lisi 100
QUEUED
127.0.0.1:6379> discard # 取消事務
OK
redis 事務樂觀鎖
樂觀鎖,即認為所有時候都不會出現問題,它不會去加鎖,他會在修改資料的時候判斷這個資料是否被改動過,如果沒有被其他人改動過,就更新資料,
在 redis 中也有樂觀鎖的操作,來防止資料出現問題,現在有如下一個場景:
你想通過事務對 redis 中的 key/value 進行修改,在沒有執行 exec 命令之前,這時候另一個 client 修改了這個 key/value,這樣再執行 exec 后可能會出現問題,這種情況下用 redis 的樂觀鎖操作就可以很輕松解決
在 redis 中有一種 check and set(CAS)的樂觀鎖操作,相關命令如下
- watch
- unwatch
watch
通過 watch 命令來監視這個 key/value,如果發現該 key/value 被修改,則呼叫 exec 時事務不會被執行
127.0.0.1:6379> watch zhangsan lisi # 監視 zhangsan 和 lisi
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby zhangsan -100
QUEUED
127.0.0.1:6379> incrby lisi 100
QUEUED
================ 這時候zhangsan的值被其他客戶端修改=======================
127.0.0.1:6379> exec # 事務執行失敗
(nil)
unwatch
取消監視,與 watch 命令相對
在執行 exec 后,不管是否執行成功,watch 命令都會 unwatched
客戶端退出后,watch 命令也會 unwatched
127.0.0.1:6379> watch zhangsan lisi # 監視 zhangsan 和 lisi
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby zhangsan -100
QUEUED
127.0.0.1:6379> incrby lisi 100
QUEUED
127.0.0.1:6379> unwatch # 取消監視
OK
和事務相關的錯誤
在 redis 事務中,可能會發生兩種錯誤
1、編譯型錯誤
在 multi 后,exec 呼叫之前,由于輸入不正確的 redis 命令導致的錯誤
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sets zhangsan 22 # 事務中命令輸錯
(error) ERR unknown command `sets`, with args beginning with: `zhangsan`, `22`,
127.0.0.1:6379> set zhangsan 22
QUEUED
127.0.0.1:6379> exec # 事務執行不成功
(error) EXECABORT Transaction discarded because of previous errors.
在這種情況下事務不會執行成功
2、運行時錯誤
在 exec 呼叫之后,由于 redis 命令執行不成功導致的錯誤
127.0.0.1:6379> set test abc
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr test # 由于test中存的不是 integer,在exec時會出錯
QUEUED
127.0.0.1:6379> set info aaa
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
從執行結果看出,在 exec 時,即使其中有命令出錯,后面的命令不會被影響,依舊會被執行從這里也可以看出,redis 不支持回滾
最后提供免費的Java架構學習資料,學習技術內容包含有:Spring,Dubbo,MyBatis, RPC, 原始碼分析,高并發、高性能、分布式,性能優化,微服務 高級架構開發等等,
點擊:點這個!點這個!暗號:csdn,
還有Java核心知識點+全套架構師學習資料和視頻+一線大廠面試寶典+面試簡歷模板可以領取+阿里美團網易騰訊小米愛奇藝快手嗶哩嗶哩面試題+Spring原始碼合集+Java架構實戰電子書,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/173062.html
標籤:其他
