redis中的事務(transaction)是一組命令的集合。事務同命令一樣都是redis的最小執行單位,乙個事務中的命令要麼都執行,要麼都不執行。
事務的原理是先將屬於乙個事務的命令傳送給redis,然後再讓redis依次執行這些命令。
> multi
ok> sadd key1 1
queued
> sadd key2 2
queued
> exec
1) (integer) 1
2) (integer) 1
首先用multi開啟事務,redis會返回"ok"。
接下來輸入的命令都會被加入到等待執行的事務佇列中,而不是像通常一樣立即執行,redis會返回"queued"表示成功加入到佇列中了。
最終需要執行時,使用exec命令告訴redis將等待執行的事務佇列中的所有命令按照傳送的順序依次執行。exec命令的返回值就是這些命令的返回值組成的列表,返回值順序和命令的順序相同。
通過這種方式,redis可以保證乙個事務中的所有命令要麼都執行,要麼都不執行。如果在傳送exec命令前客戶端斷線了,則redis會清空事務佇列,事務中的所有命令都不會執行。而一旦客戶端傳送了exec命令,所有的命令就都會被執行,即使此後客戶端斷線也沒關係,因為redis中已經記錄了所有要執行的命令。
除此之外,redis的事務還能保證乙個事務內的命令依次執行而不被其他命令插入。比如在客戶端a執行多條命令的時候,客戶端b也恰好傳送了一條命令,如果不使用事務,則客戶端b的命令可能會插入到客戶端a的命令中執行。而使用事務也可以避免這種情況的發生。
如果事務中的某個命令執行錯誤,redis怎麼處理呢?分兩種情況:
語法錯誤。命令的使用方式不對,或輸入了不存在的命令,這類情況在加入事務佇列前就會被識別出來,傳送exec後redis會直接返回錯誤提示,事務中的命令都不會被執行。
> multi
ok > set key value
queued
> set key
(error)err wrong number of arguments for 'set' command
> errorcommand key
(error)err unknown command 'errorcommand
> exec
(error) execabort transaction discarded because
of previous errors.
這裡一共三條命令,第一條被加入到事務佇列中,但後面兩條都報錯,最終事務會被取消執行。
執行錯誤。執行錯誤是指在命令執行時出現的錯誤,比如使用雜湊型別的命令操作集合型別的鍵,執行錯誤在實際執行之前是無法被redis識別的,所以在事務裡這樣的命令是會被redis接受並執行的。如果事務裡的一條命令出現了執行錯誤,事務裡其他的命令依然會繼續執行,包括出錯命令之後的命令!例如:
> multi
ok > set key 1
queued
> sadd key 2
queued
> set key 3
queued
> exec
1)ok
2) (error) err operation against a key holding
the wrong kind of value
3)ok
> get key
"3"
雖然sadd那一步執行錯誤,但接下來的set key 3仍然執行了,key的最終結果為3。
遇到這種情況怎麼辦呢?可能第一反應是如何回滾,但redis並沒有提供事務的回滾功能,一旦出現這類執行錯誤,需要使用者自行處理,手動將資料庫修復為事務執行前的狀態。
但換個角度,正是由於redis捨棄了事務的回滾功能,使得redis在的事務簡潔、快速。這裡的第一種錯誤可以被redis識別,第二種錯誤也是可以提前避免的。
在乙個事務中只有當所有命令都依次執行完後才能得到每個結果的返回值,可是有些情況下需要先獲得一條命令的返回值,然後再根據這個值執行下一條命令。如果直接獲取,可能之後這個值已經被別的客戶端更改過了,那麼後面都是基於過時的值在做計算了。
為了避免這種情況,就可以使用watch。
watch命令可以監控乙個或多個鍵,一旦其中有乙個鍵被修改(或刪除),之後的事務就不會執行。監控一直持續到exec命令(事務中的命令是在exec之後才執行的,所以在multi命令後可以修改watch監控的鍵值),如:
> set key 1
ok > watch key
ok > set key 2
ok > multi
ok > set key 3
queued
> exec
(nil)
> get key
"2"
這個例子中,在執行watch命令後、事務執行前修改了key的值(即set key 2),所以最後事務中的命令set key 3沒有執行,exec命令返回空結果。
執行exec命令後會取消對所有鍵的監控,如果不想執行事務中的命令也可以使用unwatch命令來取消監控。
redis中可以為鍵設定生存時間,可以利用這一特性,實現快取、驗證碼等功能。
expire key seconds
pexpire key milliseconds
其中seconds/milliseconds引數表示鍵的生存時間,單位是秒/毫秒。返回1表示設定成功,返回0則表示鍵不存在或設定失敗。
再次執行expire/pexpire會重置鍵的生存時間。
還可以通過設定截至時間的方式讓鍵失效:
expireat key unixtimespan
pexpireat key unixtimespan
同樣的,pexpireat的單位是毫秒。
如果想取消鍵的生存時間設定,即將鍵恢復成永久有效,可以使用persist命令:
persist key
如果生存時間被成功清除則返回1,如果鍵不存在或鍵本來就是永久的則返回0。
除了這種方法,用set命令為鍵複製也會清除鍵的生存時間。
ttl key
pttl key
ttl和pttl返回值的單位分別是秒和毫秒。
但如果鍵不存在,會返回-2。如果鍵沒有設定生存時間,或生存時間設定被清除,會返回-1。
基於生存時間可以將redis用作快取。
當伺服器記憶體有限時,如果大量地使用快取鍵且生存時間設定得過長就會導致redis佔滿記憶體;另一方面如果為了防止redis占用記憶體過大而將快取鍵的生存時間設得太短,就可能導致快取命中率過低並且大量記憶體白白地閒置。實際開發中會發現很難為快取鍵設定合理的生存時間,為此可以限制redis能夠使用的最大記憶體,並讓redis按照一定的規則淘汰不需要的快取鍵,這種方式在只將redis用作快取系統時非常實用。
修改配置檔案的maxmemory引數可以限制redis最大可用記憶體大小,當超出了這個限制時redis會依據maxmemory-policy引數指定的策略來刪除不需要的鍵,直到redis占用的記憶體小於指定記憶體。
maxmemory-policy可選的規則如下:
規則說明
volatile-lru
使用lru演算法刪除乙個鍵(只對設定了生存時間的鍵)
allkeys-lru
使用lru演算法刪除乙個鍵
volatile-random
隨機刪除乙個鍵(只對設定了生存時間的鍵)
allkeys-random
隨機刪除乙個鍵
volatile-ttl
刪除生存時間最近的乙個鍵
noeviction
不刪除鍵,只返回錯誤
lru(leastrecently used)演算法即「最近最少使用演算法」,認為最近最少使用的鍵在未來一段時間內也不會被用到,所以當需要空間時這些鍵會首先被刪除。
mybatis 事務和快取
即session快取,作用域為 session,當 session flush 或 close 之後,該session中的所有 cache 就將清空,預設開啟。在業務層執行方法時,我們通常會在方法上加事務註解 transactional,這樣的話進入方法時,就會從資料庫連線池拿取鏈結資訊,建立連線,...
Redis快取穿透和快取雪崩
了解過redis的人都知道,在執行讀操作 查詢等 的時候會先從快取中讀取,快取中沒有的話再去資料庫中查詢。如下圖 概念 使用者想要查詢乙個資料,發現redis快取中沒有,也就是快取沒有命中,於是向持久層資料庫查詢。發現也沒有,於是本次查詢失敗。當使用者很多的時候,快取都沒有命中 如秒殺 於是都去請求...
redis 快取擊穿和快取穿透
布隆過濾器 快取擊穿 總結有很多使用者,請求介面。為了防止mysql壓力過大,在訪問量很大且資料變動不頻繁的情況下,我們通過增加redis快取減少mysql的壓力。正常的流程為下圖所示。redis中無資料,從mysql中查詢 mysqlserver mysqli connect 127.0.0.1 ...