1. redis事務 使用方法:方法為先發送multi命令告訴redis,下麵所有的命令屬於同一個事務,先不要執行,而是把他們暫時存起來,redis返回OK,然後後面執行需要放在同一個事務里的命令,可以看到每個命令都會返回QUEUED表示這幾條命令已經進入等待執行的事務隊列中了,當需要在同一個事務中 ...
1. redis事務
使用方法:方法為先發送multi命令告訴redis,下麵所有的命令屬於同一個事務,先不要執行,而是把他們暫時存起來,redis返回OK,然後後面執行需要放在同一個事務里的命令,可以看到每個命令都會返回QUEUED表示這幾條命令已經進入等待執行的事務隊列中了,當需要在同一個事務中執行的命令發送完畢後,使用exec命令告訴redis將等待執行的事務隊列中的所有命令按照發送順序依次執行,exec命令的返回值就是這些命令的返回值組成的列表,返回值順序和命令執行順序一樣。
性質:redis保證一個事務中的所有命令要麼都執行,要麼都不執行。如果在發送exec命令之前客戶端斷線了,則redis會清空事務隊列,事務中所有命令都不會執行。而一旦客戶端發送了exec命令,所有的命令都會被執行,即使客戶端斷線也沒有關係,因為redis中已經記錄了所有要執行的命令。
使用場景:在需要都執行或者都不執行的情況下,或者希望執行哪幾條命令不被插入也可以使用事務。
錯誤處理:分以下兩種情況
(1)語法錯誤:語法錯誤指命令不存在或者命令參數不對,這種情況當執行exec命令後redis就會直接返回錯誤,連語法正確的命令也不會執行。(其實在輸入錯誤命令時就已經返回錯誤了,只不過不會退出隊列,所以出現錯誤時直接返回重新來就行了,因為後面就算都對執行exec後也是沒法執行的)
(2)運行錯誤:運行錯誤是指在命令執行的時候出現的錯誤,比如用散列類型的命令操作集合類型的鍵,這種錯誤在實際執行之前redis是無法發現的,所以在事務里這樣的命令是會被redis接受並執行的,如果事務里的一條命令出現了運行錯誤,事務里的其他命令依然會被執行(包括出錯命令之後的命令)。
缺點:就是沒有關係型資料庫事務提供的回滾功能,所以如果出現事務執行錯誤必須自己解決後續問題。
優點:由於redis不支持回滾功能,所以redis在事務上可以保持簡潔和快捷。
watch命令:可以監控一個或多個鍵,一旦其中一個鍵被修改或刪除,之後的事務就不會執行,監控一直持續到exec命令(事務中的命令是在exec之後才執行的,所以在multi命令後可以修改watch監控的鍵值。這裡的修改只是說向事務發送這個命令不會報錯,但其實並沒有修改,因為實際修改操作是在exec命令之後,但這個時候事務里的命令其實並沒有執行,exec命令也會返回空結果)。由於watch命令的作用只是當被監控的鍵值被修改後阻止後一個事務的執行,而不能保證其他客戶端不修改這一鍵值。執行exec命令後會取消對所有鍵的監控,如果不想執行事務中的命令也可以使用unwatch命令來取消監控
2. 生存時間
expire key seconds 給鍵設置生存時間,到期自動刪除,seconds秒數,返回1表示設置成功,返回0表示設置失敗或鍵不存在
ttl key 查看鍵還有多少時間會被刪除,返回值是剩餘的秒數,如果返回-1說明鍵永久存在,返回-2說明鍵不存在
persist key 取消鍵的生存時間,即將鍵恢覆成永久的,如果生存時間被成功清除則返回1,否則返回0(因為鍵不存在或者本身就是永久的)
使用set或getset命令為鍵賦值也會同時清除鍵的生存時間,使用expire命令會重新設置鍵的生存時間,其他只對鍵值進行操作的命令(如incr、lpush、hset、zrem)均不會影響鍵的生存時間。
expire命令的seconds參數必須是整數,如果想要更精確的控制鍵的生存時間應該使用pexpire命令,兩者唯一區別就是這個seconds參數是毫秒,同樣可以使用pttl命令以毫秒為單位返回鍵的剩餘時間。
如果使用watch命令監測一個擁有生存時間的鍵,該鍵時間到期自動刪除並不會被watch命令認為該鍵被改變。
還有兩個相關命令expireat和pexpireat,這兩個命令與原命令的差別在於這兩個seconds參數是unix時間,表示鍵的生存時間的截止時間。
過期時間這一屬性可以把redis用作緩存,比如登錄功能,登錄成功放入緩存中,設置一個過期時間,如有則認為已經登錄,如果過期刪除則需要重新登錄。
實際開發中如果緩存鍵生存時間太長會導致redis占滿記憶體,如果太短可能導致緩存命中率太低並且大量記憶體被白白的閑置,為此可以限制redis能夠使用的最大記憶體,並讓redis按照一定的規則淘汰不需要的緩存鍵,這種方式在只將redis用作緩存系統時非常實用。
具體設置方法為:修改配置文件的maxmemory參數,限制redis最大可用記憶體大小(單位是位元組),當超出了這個限制時redis會根據maxmemory-policy參數指定的策略來刪除不需要的鍵,直到redis占用的記憶體小於指定記憶體。maxmemory-policy支持的規則如下:(LRU演算法即"最長時間未被使用的",LFU演算法即"一段時間使用最少的")
volatile-lru 使用LRU演算法刪除一個鍵(只對設置了生存時間的鍵)
volatile-lfu 使用LFU演算法刪除一個鍵(只對設置了生存時間的鍵)
volatile-random 隨機刪除一個鍵(只對設置了生存時間的鍵)
allkeys-lru 使用LRU演算法刪除一個鍵(所有)
allkeys-lfu 使用LFU演算法刪除一個鍵(所有)
allkeys-random 隨機刪除一個鍵(所有)
volatile-ttl 從設置了過期時間的鍵中選擇過期時間最早的鍵刪除
noeviction 不刪除鍵,只返回錯誤
使用maxmemory-poliy參數刪除鍵時redis並不會準確的從整個資料庫中查找,而是每次隨機取3個鍵並刪除這三個鍵中符合條件的,3這個數字可以通過redis的配置文件中的maxmemory-samples參數設置。
3. 排序
基本排序:
sort key [alpha] [desc] [limit start end] 該命令可以給集合和有序集合進行排序,當給有序集合排序時會忽略元素的分數,只針對元素本身的值進行排序。如果要按照ASCLL碼排序非數字元素,需要加上"alpha",倒序需要加上desc,分頁需要加上limit,方法和mysql資料庫一樣。
by參數:
有時候排序不一定完全按照集合中的元素值本身排序,而是會根據別的元素作為相關鍵進行排序,這時候就用到了by參數。
by參數的語法"by參考鍵",其中參考鍵可以是字元串類型鍵或者是散列類型鍵的某個欄位(表示為鍵名->欄位名)。如果提供了by參數,sort命令將不再依據元素自身的值進行排序,而是對每個元素使用元素的值替換參考鍵中的第一個"*"並獲取其值,然後依據該值對元素排序。
當參考鍵名不包含"*"時(即常量鍵名,與元素值無關),sort命令將不會執行排序操作,因為redis認為這種情況是沒有意義的(因為所有要比較的值都一樣)。
在不需要排序但是需要藉助sort命令獲得與元素相關聯的數據時,常量鍵名是很有用的。
如果幾個元素的參考鍵值相同,則sort命令會再比較元素本身的值決定元素的順序。
當某個元素的參考鍵不存在時,會預設參考鍵的值為0。
參考鍵雖然支持散列類型,但是"*"只能在"->"符號前面(即鍵名部分)才有用,在後面(即欄位名部分)會被當成欄位名本身而不會作為占位符被元素的值替換,即常量鍵名,這樣的結果就是依舊會按照元素本身的值進行排序,因為參考鍵如果是常量redis不會進行排序,但是檢測是否是常量的方法是判斷參考鍵中是否含有"*",上面顯然含有,所以不會被當成常量不排序,而排序的話每個元素的參考值是相通的,所以redis會按照元素本身的大小排序。
get參數:
get參數可以指定排序後返回的鍵值。get參數不影響排序,它的作用是使sort命令的返回結果不再是元素自身的值,而是get參數中指定的鍵值,get參數的規則和by參數的一樣,get參數也支持字元串類型和散列類型的鍵,並使用"*"作為占位符。一個sort命令中可以有多個get參數,在後面直接加就可以了。如果還需要返回原來的元素值,可以使用"get #"。
store參數:
預設情況下sort會直接返回排序後的結果,如果希望保存排序結果可以使用store參數。後面加命令"store key"即可保存在key中,保存後的鍵的類型為列表類型,如果鍵已經存在則會覆蓋它,加上store參數後sort命令的返回值為結果的個數。
性能優化:
sort命令是redis中最強大最複雜的命令,使用不好容易成為性能瓶頸,redis在排序前會建立一個長度等同於要排序的集合中的元素個數的容器來存儲待排序的元素,雖然是一個臨時的過程,但如果同時進行較多的大數據量排序操作則會嚴重影響性能。所以開發中使用sort命令時需要註意以下幾點:
(1)儘可能減少待排序鍵中元素的數量;
(2)儘量使用limit參數只獲取需要的數據;
(3)如果要排序的數據數量較大,儘可能使用store參數將結果緩存。
4. 消息通知
使用redis實現任務隊列:
(1)簡單隊列概念
使用loush和rpop命令可以實現隊列的概念,但是這樣即使隊列中沒有任務也會一直調用rpop命令查看是否有新任務,最好可以實現有新任務加入隊列時通知調用者就好了。這裡再介紹一個命令brpop。
brpop命令接收兩個參數,第一個是鍵名,第二個是超時時間,單位是秒。當超過了此時間仍然沒有獲得新元素的話就會返回nil。如果超時時間設置為0的話,表示不限制等待時間,即如果沒有新元素加入隊列就會永遠阻塞下去。
除了brpop名另外,還有blpop命令,即從左取元素。
(2)隊列優先順序問題
brpop命令可以同時接收多個鍵,其完整的命令格式為"blpop key1 [key2...] timeout",意思是同時檢測多個鍵,如果所有鍵都沒有元素則阻塞,如果其中有一個鍵有元素則會從該鍵中彈出元素。如果多個鍵都有元素,則會按照從左到右的順序取第一個鍵中的一個元素。這樣如果想要設置優先順序,比如先取哪個隊列中的元素,只要把它放在blpop前面的參數即可,這樣只要第一個鍵里有元素,不管第二個鍵里有多少個元素都會先從第一個鍵中取出。
(3)發佈/訂閱模式
發佈訂閱模式中包含兩種角色,分別是發佈者和訂閱者。訂閱者可以訂閱一個或多個頻道,而發佈者可以向指定的頻道發送消息,所以訂閱此頻道的訂閱者都會收到此消息。
發佈者發佈消息的命令是publish,用法是publish channel message,該命令返回值表示收到這條消息的訂閱者數量。發出的消息不會被持久化,也就是說客戶端訂閱某頻道之後只能收到後續發佈的該頻道的消息,之前發送的就收不到了。
subscribe channel [channel...] 訂閱頻道,可以多個
執行過訂閱命令後客戶端會進入訂閱狀態,處於此狀態下客戶端不能使用除subscribe/unsubscribe/psubscribe/punsubscribe這四個屬於發佈訂閱模式的命令之外的命令,否則會報錯。
進入訂閱狀態後客戶端可能收到三種類型回覆,每種類型回覆都包含三個值,第一個值是消息的類型,根據消息類型不同,第二、三個值的含義也不同。消息類型可能的值有:
Subscribe。表示訂閱成功的反饋信息。第二個值是訂閱成功的頻道名稱,第三個值是當前客戶端訂閱的頻道數量。
message。這個類型的回覆是我們最關心的,它表示接收到的消息,第二個值表示產生消息的頻道名稱,第三個值是消息的內容。
unsubscribe。表示成功取消訂閱某個頻道。第二個值是對應的頻道名稱,第三個值是當前客戶端訂閱的頻道數量,當此值為0時客戶端會退出訂閱狀態,之後就可以執行其他非發佈訂閱模式的命令了。
unsubscribe [channel [channel ...]] 取消訂閱指定頻道,如果不指定則會取消訂閱所有頻道。
(4)按照規則訂閱
可以使用psubscribe命令訂閱指定的規則,規則支持glob風格通配符格式。
當使用psubscribe命令訂閱時,收到的message類型回覆會有所改變,一共四個值,第一個是pmessage而不是message,第二個是訂閱時使用的通配符,第三個值表示實際收到消息的頻道命令,第四個值則表示消息內容。
使用psubscribe命令可以重覆訂閱一個頻道,如某客戶端執行了psubscribe channel.? channel.?*,這時向channel.2發佈消息後該客戶端會收到兩條消息,而同時publish命令返回的值也是2而不是1。同樣的,如果另一個客戶端執行了subscribe channel.10,和psubscribe channel.?*的話,向channel.10發送命令該客戶端也會收到兩條消息(但是是兩種類型,message和pmessage),同時publish命令會返回2。
punsubscribe命令可以退訂指定的規則,用法是punsubscribe [pattern [pattern ...]],如果沒有參數會退訂所有的規則。
使用punsubscribe命令只能退訂通過psubscribe命令訂閱的規則,不會影響直接通過subscribe命令訂閱的頻道;同樣unsubscribe命令也不會影響通過psubscribe命令訂閱的規則。另外容易出錯的一點是使用punsubscribe命令退訂某個規則時不會將其中的通配符展開,而是進行嚴格的字元串匹配,所以punsubscribe *無法退訂channel.*規則,而是必須使用punsubscribe channel.*才能退訂。