Python--Redis實戰:第三章:Redis命令:第七節:其餘命令

上一篇文章: Python--Redis實戰:第三章:Redis命令:第六節:發佈與訂閱
下一篇文章: Python--Redis實戰:第四章:數據安全與性能保障:第1節:持久化選項

到目前爲止,本章介紹了Redis提供的5種結構以及Redis的發佈與訂閱模式。本節將要介紹的命令則能夠用於處理多種類型的數據:首先要介紹的是能夠同時處理字符串、集合、列表和散列的sort命令;以後要介紹的是用於實現基本事務特性的multi命令和exec命令,這兩個命令可讓用戶將多個命令當作一個命令來執行;最後要介紹的是幾個不一樣的自動過時命令,他們能夠自動刪除無用的數據。redis

閱讀本節有助於讀者更好的理解如何同時組合和操做多種數據類型。sql

排序

Redis的排序操做和其餘編程語言的排序操做同樣,均可以根據某種比較規則對一系列元素進行有序排列。負責執行排序操做的sort命令能夠根據字符串、列表、集合、有序集合、散列這5種鍵Kim存儲的數據,對列表、集合以及有序集合進行排序。若是讀者以前曾經使用過關係數據庫的話,那麼能夠將soft命令看作是sql語言裏的order by。數據庫

下表展現了sort命令的定義:編程

命令 用例 用例描述
soft soft source-key [by pattern] [limit offset count] [get pattern get pattern ...]] [asc/desc] [alph] [store dest-key] 根據給定的選項,對輸入列表、集合或者有序集合進行排序,而後返回或者存儲排序的結果。

使用sort命令提供的選項能夠實現如下功能:segmentfault

  • 根據降序而不是默認的升序來排列元素;
  • 將元素看做是數字來進行排序,或者將元素看做是二進制字符串來進行排序(好比排序字符串'110'和'12'的排序結果就跟排序數字110和12的結果不同);
  • 使用被排序元素以外的其餘值做爲權重進行排序,甚至還能夠從輸入的列表、集合、有序集合之外的其餘地方進行取值。

實例

import redis # 導入redis包包


# 與本地redis進行連接,地址爲:localhost,端口號爲6379
r = redis.StrictRedis(host='localhost', port=6379)
r.delete('sort-input')

#首先將一些元素添加到列表裏面
print(r.rpush('sort-input',23,15,110,7))
#根據數字大小對元素進行排序
print(r.sort('sort-input'))
#根據字母順序對元素進行排序
print(r.sort('sort-input',alpha=True))

#添加一些用於執行排序操做和獲取操做的附加數據
print(r.hset('d-7','field',5))
print(r.hset('d-15','field',1))
print(r.hset('d-23','field',9))
print(r.hset('d-110','field',3))

#將散列的域(field)用做權重,對sort-input列表進行排序
print(r.sort('sort-input',by='d-*->field'))

#獲取外部數據,並將它們用做命令的返回值,而不是返回被排序的數據
print(r.sort('sort-input',by='d-*->field',get='d-*->field'))

運行結果:緩存

4
[b'7', b'15', b'23', b'110']
[b'110', b'15', b'23', b'7']
0
0
0
0
[b'15', b'110', b'7', b'23']
[b'1', b'3', b'5', b'9']
最開頭的幾行代碼設置了一些初始數據,而後對這些數據進行了數值排序和字符串排序,最後的代碼演示了若是經過sort命令的特殊語法來將散列存儲的數據做爲權重進行排序,以及怎樣獲取並返回散列存儲的數據。

sort命令不只能夠對列表進行排序,還能夠對集合進行排序,而後返回一個列表形式的排序結果。上述實例除了展現了若是使用alpha關鍵字參數對元素進行字符串排序以外,還展現了若是基於外部數據對元素進行排序,以及如何獲取並返回外部數據。安全

後面講介紹如何組合使用集合操做和sort命令:當集合結構計算交集、並集和差集的能力,與sort命令獲取散列存儲的外部數據的能力相結合時,sort命令將變得很是強大。編程語言

儘管sort是Redis中惟一一個能夠同時處理3種不一樣類型的數據的命令,但基本的Redis事務一樣可讓咱們在一連串不斷執行的命令裏面操做多種不一樣類型的數據。性能

基本的Redis事務

有時候爲了同時處理多個結構,咱們須要向Redis發送多個命令。儘管Redis有幾個能夠在兩個鍵之間複製或者移動元素,但卻沒有那種能夠在兩個不一樣類型之間移動元素的命令(雖然可使用zunionstore命令將元素從一個集合複製到一個有序集合)。爲了對相同或者不一樣類型的多個鍵執行操做,Redis有5個命令可讓用戶在不被打斷(interruption)的狀況下對多個鍵執行操做,它們分別是watch、multi、exec、unwatch、discard。線程

這一節中介紹最基本的Redis事務用法,其中只會用到multi命令和exec命令。

什麼是Redis的基本事務

Redis的基本事務須要用到multi命令和exec命令,這種事務可讓一個客戶端在不被其餘客戶端打斷的狀況下執行多個命令。和關係數據庫那種能夠在執行的過程當中進行回滾(rollback)的事務不一樣,在Redis裏面,被multi命令和exec命令包圍的全部命令會一個接一個的執行,直到全部命令都執行完畢。當一個事務執行完畢以後,Redis纔會處理其餘客戶端的命令。

要在Redis裏面執行事務,咱們首先須要執行multi命令,而後輸入那些咱們想要在事務裏面執行的命令,最後再執行exec命令。當Redis從一個客戶端那裏接受到multi命令時,Redis會將這個客戶端以後發送的全部命令都放入到一個隊列裏面,直到這個客戶端發送exec命令爲止,而後Redis就會在不被打斷的狀況下,一個接一個地執行存儲在隊列裏面的命令。從語義上來講,Redis事務在Python客戶端上面是由流水線(pipelien)實現:對鏈接對象用pipeline()方法將建立一個事務,在一切正常的狀況下,客戶端會自動地使用multi和exec包裹起用戶輸入的多個命令。此處,爲了減小Redis與客戶端之間的通訊往返次數,提高執行多個命令時的性能,Python的Redis客戶端會存儲起事務包含的多個命令,而後在事務執行時一次性地將全部命令都發送給Redis。

跟介紹publish命令和subscribe命令時的狀況同樣,要展現事務執行結果,最簡單的方法就是將事務放到線程裏執行。

下面代碼展現了在沒有使用事務的狀況下,執行並行(parallel)自增操做的結果:

import redis  # 導入redis包包
import time,threading


# 與本地redis進行連接,地址爲:localhost,端口號爲6379
r = redis.StrictRedis(host='localhost', port=6379)
r.delete('notrans:')

def notrans():
    #對'notrans:'計數器執行自增操做並打印操做的執行結果
    print(r.incr('notrans:'))
    #等待100毫秒
    time.sleep(.1)
    #對'notrans:'計數器執行自減操做。
    r.incr('notrans:',-1)


if __name__ == '__main__':
    # 啓動3個線程來執行沒有被事務包裹的自增、休眠和自減操做
    for i in range(3):
        threading.Thread(target=notrans).start()
    # 等待500毫秒,讓操做有足夠的時間完成
    time.sleep(.5)

結果:

1
2
3

由於沒有使用事務,因此三個線程均可以在執行自減操做以前,對notrans:計數器執行自增操做。雖然代碼裏面經過休眠100毫秒放大了潛在問題,但若是咱們確實須要在不受其它命令干擾的狀況下,對計數器執行自增操做和自減操做,那麼咱們就不得不解決這個潛在問題。

下面代碼使用事務來執行相同的操做:

import redis  # 導入redis包包
import time,threading


# 與本地redis進行連接,地址爲:localhost,端口號爲6379
r = redis.StrictRedis(host='localhost', port=6379)
r.delete('trans:')

def notrans():
    #建立一個事務型(transactional)流水線對象
    pipeline=r.pipeline()
    #把針對'trans:'計數器的自增操做放入隊列
    pipeline.incr('trans:')
    #等待100毫秒
    time.sleep(.1)
    #把針對'trans:'計數器的自減操做放入隊列
    pipeline.incr('trans:',-1)
    #執行被事務包裹的命令,並打印自增操做的執行結果
    print(pipeline.execute()[0])


if __name__ == '__main__':
    # 啓動3個線程來執行沒有被事務包裹的自增、休眠和自減操做
    for i in range(3):
        threading.Thread(target=notrans).start()
    # 等待500毫秒,讓操做有足夠的時間完成
    time.sleep(.5)

結果:

1
1
1

能夠看出,儘管自增操做和自減操做直接有一段延遲時間,但經過使用事務,各個線程均可以在不被其它線程打斷的狀況下,執行各自隊列裏面的命令。記住,Redis要在接收到Exec命令以後,纔會執行那些位於multi和exec之間的入隊命令。

在使用Redis存儲數據的時候,有些數據僅在一段很短的時間內有用,雖然咱們能夠在數據的有效期過了以後刪除無用的數據,但更好的辦法是使用Redis提供的鍵過時操做來自動刪除無用數據。

鍵的過時時間

在使用Redis存儲數據的時候,有些數據可能在某個時間點以後就再也不有用了,用戶可使用DEL命令顯示刪除這些無用數據,也能夠經過Redis的過時時間(expiration)特徵來讓一個鍵再給定的時限(timeout)以後自動被刪除。當咱們說一個鍵【帶有生存時間】(time to live)或者一個鍵【會在特定時間以後過時】時,咱們指的是Redis會在這個鍵的過時時間到達時自動刪除該鍵。

雖然過時時間特性對於清理緩存數據很是有用,不過一般只有少數幾個命令能夠原子地爲鍵設置過時時間,而且對於列表、集合、散列和有序集合這樣的容器來講,鍵過時命令只能爲整個鍵設置過時時間,而沒辦法爲鍵裏面的單個元素設置過時時間(爲了解決這個問題,可使用存儲時間戳的有序集合來實現針對的那個元素的過時操做)。

本節將對那些能夠在給定時限或者給定時間以後,自動刪除過時鍵的Redis命令進行介紹。經過閱讀本節,讀者能夠學會如何使用過時操做來自動刪除過時數據並下降Redis的內存佔用。

下表列出了Redis提供的用於爲鍵設置過時時間的命令,已經查看鍵的過時時間的命令:

命令 示例 描述
persist persist key-name 移除鍵的過時時間
ttl ttl key-name 查看給定鍵距離過時還有多少秒
expire expire key-name seconds 讓給定鍵再指定的秒數以後過時
expireat expireat key-name timestamp 將給定鍵的過時時間設置爲給定的UNIX時間戳。
pttl pttl key-name 查看給定鍵距離過時時間還有多少毫秒,這個命令在Redis2.6或以上版本可用,
pexpire pexpire key-name milliseconds 讓給定鍵再指定的毫秒以後過時。這個命令在Redis2.6或以上版本可用。
pexpireat pexpireat key-name timestamp-milliseconds 將一個毫秒級精確的UNIX時間戳設置爲給定鍵的過時時間,這個命令在Redis2.6或以上版本可用。

下面代碼展現了幾個對鍵執行過時時間操做的例子:

import redis # 導入redis包包
import time


# 與本地redis進行連接,地址爲:localhost,端口號爲6379
r = redis.StrictRedis(host='localhost', port=6379)
r.delete('trans:')

#設置一個簡單的字符串值做爲過時時間的設置對象
print(r.set('key','value'))
print(r.get('key'))
print(r.expire('key',2))

time.sleep(1)

#查看鍵距離過時還有多長時間
print(r.ttl('key'))

time.sleep(1)

#此時鍵已通過期,並被刪除
print(r.get('key'))

運行結果:

True
b'value'
True
1
None
上一篇文章: Python--Redis實戰:第三章:Redis命令:第六節:發佈與訂閱
下一篇文章: Python--Redis實戰:第四章:數據安全與性能保障:第1節:持久化選項
相關文章
相關標籤/搜索