Python--Redis实战:第三章:Redis命令:第七节:其他命令
下一篇文章:Python--Redis實(shí)戰(zhàn):第四章:數(shù)據(jù)安全與性能保障:第1節(jié):持久化選項(xiàng)
到目前為止,本章介紹了Redis提供的5種結(jié)構(gòu)以及Redis的發(fā)布與訂閱模式。本節(jié)將要介紹的命令則可以用于處理多種類型的數(shù)據(jù):首先要介紹的是可以同時(shí)處理字符串、集合、列表和散列的sort命令;之后要介紹的是用于實(shí)現(xiàn)基本事務(wù)特性的multi命令和exec命令,這兩個(gè)命令可以讓用戶將多個(gè)命令當(dāng)做一個(gè)命令來執(zhí)行;最后要介紹的是幾個(gè)不同的自動(dòng)過期命令,亞麻可以自動(dòng)刪除無用的數(shù)據(jù)。
閱讀本節(jié)有助于讀者更好的理解如何同時(shí)組合和操作多種數(shù)據(jù)類型。
排序
Redis的排序操作和其他編程語言的排序操作一樣,都可以根據(jù)某種比較規(guī)則對(duì)一系列元素進(jìn)行有序排列。負(fù)責(zé)執(zhí)行排序操作的sort命令可以根據(jù)字符串、列表、集合、有序集合、散列這5種鍵Kim存儲(chǔ)的數(shù)據(jù),對(duì)列表、集合以及有序集合進(jìn)行排序。如果讀者之前曾經(jīng)使用過關(guān)系數(shù)據(jù)庫的話,那么可以將soft命令看做是sql語言里的order by。
下表展示了sort命令的定義:
| soft | soft source-key [by pattern] [limit offset count] [get pattern get pattern ...]] [asc/desc] [alph] [store dest-key] | 根據(jù)給定的選項(xiàng),對(duì)輸入列表、集合或者有序集合進(jìn)行排序,然后返回或者存儲(chǔ)排序的結(jié)果。 |
使用sort命令提供的選項(xiàng)可以實(shí)現(xiàn)以下功能:
- 根據(jù)降序而不是默認(rèn)的升序來排列元素;
- 將元素看作是數(shù)字來進(jìn)行排序,或者將元素看作是二進(jìn)制字符串來進(jìn)行排序(比如排序字符串'110'和'12'的排序結(jié)果就跟排序數(shù)字110和12的結(jié)果不一樣);
- 使用被排序元素之外的其他值作為權(quán)重進(jìn)行排序,甚至還可以從輸入的列表、集合、有序集合以外的其他地方進(jìn)行取值。
實(shí)例
import redis # 導(dǎo)入redis包包# 與本地redis進(jìn)行鏈接,地址為:localhost,端口號(hào)為6379 r = redis.StrictRedis(host='localhost', port=6379) r.delete('sort-input')#首先將一些元素添加到列表里面 print(r.rpush('sort-input',23,15,110,7)) #根據(jù)數(shù)字大小對(duì)元素進(jìn)行排序 print(r.sort('sort-input')) #根據(jù)字母順序?qū)υ剡M(jìn)行排序 print(r.sort('sort-input',alpha=True))#添加一些用于執(zhí)行排序操作和獲取操作的附加數(shù)據(jù) 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)用作權(quán)重,對(duì)sort-input列表進(jìn)行排序 print(r.sort('sort-input',by='d-*->field'))#獲取外部數(shù)據(jù),并將它們用作命令的返回值,而不是返回被排序的數(shù)據(jù) print(r.sort('sort-input',by='d-*->field',get='d-*->field'))運(yùn)行結(jié)果:
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'] 最開頭的幾行代碼設(shè)置了一些初始數(shù)據(jù),然后對(duì)這些數(shù)據(jù)進(jìn)行了數(shù)值排序和字符串排序,最后的代碼演示了如果通過sort命令的特殊語法來將散列存儲(chǔ)的數(shù)據(jù)作為權(quán)重進(jìn)行排序,以及怎樣獲取并返回散列存儲(chǔ)的數(shù)據(jù)。sort命令不僅可以對(duì)列表進(jìn)行排序,還可以對(duì)集合進(jìn)行排序,然后返回一個(gè)列表形式的排序結(jié)果。上述實(shí)例除了展示了如果使用alpha關(guān)鍵字參數(shù)對(duì)元素進(jìn)行字符串排序之外,還展示了如果基于外部數(shù)據(jù)對(duì)元素進(jìn)行排序,以及如何獲取并返回外部數(shù)據(jù)。
后面講介紹如何組合使用集合操作和sort命令:當(dāng)集合結(jié)構(gòu)計(jì)算交集、并集和差集的能力,與sort命令獲取散列存儲(chǔ)的外部數(shù)據(jù)的能力相結(jié)合時(shí),sort命令將變得非常強(qiáng)大。
盡管sort是Redis中唯一一個(gè)可以同時(shí)處理3種不同類型的數(shù)據(jù)的命令,但基本的Redis事務(wù)同樣可以讓我們?cè)谝贿B串不斷執(zhí)行的命令里面操作多種不同類型的數(shù)據(jù)。
基本的Redis事務(wù)
有時(shí)候?yàn)榱送瑫r(shí)處理多個(gè)結(jié)構(gòu),我們需要向Redis發(fā)送多個(gè)命令。盡管Redis有幾個(gè)可以在兩個(gè)鍵之間復(fù)制或者移動(dòng)元素,但卻沒有那種可以在兩個(gè)不同類型之間移動(dòng)元素的命令(雖然可以使用zunionstore命令將元素從一個(gè)集合復(fù)制到一個(gè)有序集合)。為了對(duì)相同或者不同類型的多個(gè)鍵執(zhí)行操作,Redis有5個(gè)命令可以讓用戶在不被打斷(interruption)的情況下對(duì)多個(gè)鍵執(zhí)行操作,它們分別是watch、multi、exec、unwatch、discard。
這一節(jié)中介紹最基本的Redis事務(wù)用法,其中只會(huì)用到multi命令和exec命令。
什么是Redis的基本事務(wù)
Redis的基本事務(wù)需要用到multi命令和exec命令,這種事務(wù)可以讓一個(gè)客戶端在不被其他客戶端打斷的情況下執(zhí)行多個(gè)命令。和關(guān)系數(shù)據(jù)庫那種可以在執(zhí)行的過程中進(jìn)行回滾(rollback)的事務(wù)不同,在Redis里面,被multi命令和exec命令包圍的所有命令會(huì)一個(gè)接一個(gè)的執(zhí)行,直到所有命令都執(zhí)行完畢。當(dāng)一個(gè)事務(wù)執(zhí)行完畢之后,Redis才會(huì)處理其他客戶端的命令。
要在Redis里面執(zhí)行事務(wù),我們首先需要執(zhí)行multi命令,然后輸入那些我們想要在事務(wù)里面執(zhí)行的命令,最后再執(zhí)行exec命令。當(dāng)Redis從一個(gè)客戶端那里接受到multi命令時(shí),Redis會(huì)將這個(gè)客戶端之后發(fā)送的所有命令都放入到一個(gè)隊(duì)列里面,直到這個(gè)客戶端發(fā)送exec命令為止,然后Redis就會(huì)在不被打斷的情況下,一個(gè)接一個(gè)地執(zhí)行存儲(chǔ)在隊(duì)列里面的命令。從語義上來說,Redis事務(wù)在Python客戶端上面是由流水線(pipelien)實(shí)現(xiàn):對(duì)連接對(duì)象用pipeline()方法將創(chuàng)建一個(gè)事務(wù),在一切正常的情況下,客戶端會(huì)自動(dòng)地使用multi和exec包裹起用戶輸入的多個(gè)命令。此處,為了減少Redis與客戶端之間的通信往返次數(shù),提升執(zhí)行多個(gè)命令時(shí)的性能,Python的Redis客戶端會(huì)存儲(chǔ)起事務(wù)包含的多個(gè)命令,然后在事務(wù)執(zhí)行時(shí)一次性地將所有命令都發(fā)送給Redis。
跟介紹publish命令和subscribe命令時(shí)的情況一樣,要展示事務(wù)執(zhí)行結(jié)果,最簡(jiǎn)單的方法就是將事務(wù)放到線程里執(zhí)行。
下面代碼展示了在沒有使用事務(wù)的情況下,執(zhí)行并行(parallel)自增操作的結(jié)果:
import redis # 導(dǎo)入redis包包 import time,threading# 與本地redis進(jìn)行鏈接,地址為:localhost,端口號(hào)為6379 r = redis.StrictRedis(host='localhost', port=6379) r.delete('notrans:')def notrans():#對(duì)'notrans:'計(jì)數(shù)器執(zhí)行自增操作并打印操作的執(zhí)行結(jié)果print(r.incr('notrans:'))#等待100毫秒time.sleep(.1)#對(duì)'notrans:'計(jì)數(shù)器執(zhí)行自減操作。r.incr('notrans:',-1)if __name__ == '__main__':# 啟動(dòng)3個(gè)線程來執(zhí)行沒有被事務(wù)包裹的自增、休眠和自減操作for i in range(3):threading.Thread(target=notrans).start()# 等待500毫秒,讓操作有足夠的時(shí)間完成time.sleep(.5)結(jié)果:
1 2 3因?yàn)闆]有使用事務(wù),所以三個(gè)線程都可以在執(zhí)行自減操作之前,對(duì)notrans:計(jì)數(shù)器執(zhí)行自增操作。雖然代碼里面通過休眠100毫秒放大了潛在問題,但如果我們確實(shí)需要在不受其它命令干擾的情況下,對(duì)計(jì)數(shù)器執(zhí)行自增操作和自減操作,那么我們就不得不解決這個(gè)潛在問題。
下面代碼使用事務(wù)來執(zhí)行相同的操作:
import redis # 導(dǎo)入redis包包 import time,threading# 與本地redis進(jìn)行鏈接,地址為:localhost,端口號(hào)為6379 r = redis.StrictRedis(host='localhost', port=6379) r.delete('trans:')def notrans():#創(chuàng)建一個(gè)事務(wù)型(transactional)流水線對(duì)象pipeline=r.pipeline()#把針對(duì)'trans:'計(jì)數(shù)器的自增操作放入隊(duì)列pipeline.incr('trans:')#等待100毫秒time.sleep(.1)#把針對(duì)'trans:'計(jì)數(shù)器的自減操作放入隊(duì)列pipeline.incr('trans:',-1)#執(zhí)行被事務(wù)包裹的命令,并打印自增操作的執(zhí)行結(jié)果print(pipeline.execute()[0])if __name__ == '__main__':# 啟動(dòng)3個(gè)線程來執(zhí)行沒有被事務(wù)包裹的自增、休眠和自減操作for i in range(3):threading.Thread(target=notrans).start()# 等待500毫秒,讓操作有足夠的時(shí)間完成time.sleep(.5)結(jié)果:
1 1 1可以看出,盡管自增操作和自減操作直接有一段延遲時(shí)間,但通過使用事務(wù),各個(gè)線程都可以在不被其它線程打斷的情況下,執(zhí)行各自隊(duì)列里面的命令。記住,Redis要在接收到Exec命令之后,才會(huì)執(zhí)行那些位于multi和exec之間的入隊(duì)命令。
在使用Redis存儲(chǔ)數(shù)據(jù)的時(shí)候,有些數(shù)據(jù)僅在一段很短的時(shí)間內(nèi)有用,雖然我們可以在數(shù)據(jù)的有效期過了之后刪除無用的數(shù)據(jù),但更好的辦法是使用Redis提供的鍵過期操作來自動(dòng)刪除無用數(shù)據(jù)。
鍵的過期時(shí)間
在使用Redis存儲(chǔ)數(shù)據(jù)的時(shí)候,有些數(shù)據(jù)可能在某個(gè)時(shí)間點(diǎn)之后就不再有用了,用戶可以使用DEL命令顯示刪除這些無用數(shù)據(jù),也可以通過Redis的過期時(shí)間(expiration)特征來讓一個(gè)鍵再給定的時(shí)限(timeout)之后自動(dòng)被刪除。當(dāng)我們說一個(gè)鍵【帶有生存時(shí)間】(time to live)或者一個(gè)鍵【會(huì)在特定時(shí)間之后過期】時(shí),我們指的是Redis會(huì)在這個(gè)鍵的過期時(shí)間到達(dá)時(shí)自動(dòng)刪除該鍵。
雖然過期時(shí)間特性對(duì)于清理緩存數(shù)據(jù)非常有用,不過通常只有少數(shù)幾個(gè)命令可以原子地為鍵設(shè)置過期時(shí)間,并且對(duì)于列表、集合、散列和有序集合這樣的容器來說,鍵過期命令只能為整個(gè)鍵設(shè)置過期時(shí)間,而沒辦法為鍵里面的單個(gè)元素設(shè)置過期時(shí)間(為了解決這個(gè)問題,可以使用存儲(chǔ)時(shí)間戳的有序集合來實(shí)現(xiàn)針對(duì)的那個(gè)元素的過期操作)。
本節(jié)將對(duì)那些可以在給定時(shí)限或者給定時(shí)間之后,自動(dòng)刪除過期鍵的Redis命令進(jìn)行介紹。通過閱讀本節(jié),讀者可以學(xué)會(huì)如何使用過期操作來自動(dòng)刪除過期數(shù)據(jù)并降低Redis的內(nèi)存占用。
下表列出了Redis提供的用于為鍵設(shè)置過期時(shí)間的命令,已經(jīng)查看鍵的過期時(shí)間的命令:
| persist | persist key-name | 移除鍵的過期時(shí)間 |
| ttl | ttl key-name | 查看給定鍵距離過期還有多少秒 |
| expire | expire key-name seconds | 讓給定鍵再指定的秒數(shù)之后過期 |
| expireat | expireat key-name timestamp | 將給定鍵的過期時(shí)間設(shè)置為給定的UNIX時(shí)間戳。 |
| pttl | pttl key-name | 查看給定鍵距離過期時(shí)間還有多少毫秒,這個(gè)命令在Redis2.6或以上版本可用, |
| pexpire | pexpire key-name milliseconds | 讓給定鍵再指定的毫秒之后過期。這個(gè)命令在Redis2.6或以上版本可用。 |
| pexpireat | pexpireat key-name timestamp-milliseconds | 將一個(gè)毫秒級(jí)精確的UNIX時(shí)間戳設(shè)置為給定鍵的過期時(shí)間,這個(gè)命令在Redis2.6或以上版本可用。 |
下面代碼展示了幾個(gè)對(duì)鍵執(zhí)行過期時(shí)間操作的例子:
import redis # 導(dǎo)入redis包包 import time# 與本地redis進(jìn)行鏈接,地址為:localhost,端口號(hào)為6379 r = redis.StrictRedis(host='localhost', port=6379) r.delete('trans:')#設(shè)置一個(gè)簡(jiǎn)單的字符串值作為過期時(shí)間的設(shè)置對(duì)象 print(r.set('key','value')) print(r.get('key')) print(r.expire('key',2))time.sleep(1)#查看鍵距離過期還有多長(zhǎng)時(shí)間 print(r.ttl('key'))time.sleep(1)#此時(shí)鍵已經(jīng)過期,并被刪除 print(r.get('key'))運(yùn)行結(jié)果:
True b'value' True 1 None 上一篇文章:Python--Redis實(shí)戰(zhàn):第三章:Redis命令:第六節(jié):發(fā)布與訂閱下一篇文章:Python--Redis實(shí)戰(zhàn):第四章:數(shù)據(jù)安全與性能保障:第1節(jié):持久化選項(xiàng)
總結(jié)
以上是生活随笔為你收集整理的Python--Redis实战:第三章:Redis命令:第七节:其他命令的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑桌面有图标删除不了怎么办?(win1
- 下一篇: python爬取歌曲评论并进行数据可视化