Python實現(xiàn)操作Redis的高級用法分享
redis-py
redis-py是Python操作Redis的第三方庫,它提供了與Redis服務器交互的API。
GitHub地址:https://github.com/redis/redis-py
安裝redis-py
pip install redis
基本使用
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.Redis(host='localhost', port=6379, db=0)
# 設置鍵值對
r.set('hello', 'world')
# 獲取鍵對應的值
value = r.get('hello')
# 輸出 b'world'
print(value)
# 批量設置鍵值對
r.mset({'foo': '1', 'bar': '2'})
# 批量獲取鍵對應的值
values = r.mget(['foo', 'bar'])
# 輸出 [b'1', b'2']
print(values)也可以使用StrictRedis對象連接redis服務器,StrictRedis類基于Redis類實現(xiàn)。
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 設置鍵值對
r.set('hello', 'world')
# 獲取鍵對應的值
value = r.get('hello')
print(value) # 輸出 b'world'增刪改查
以操作String數(shù)據(jù)類型的增刪改查為例。
# 引?模塊
import redis
if __name__ == '__main__':
try:
# 創(chuàng)建Redis對象
r = redis.Redis(host='localhost', port=6379, db=0)
# 新增,添加成功則返回True,如果添加失敗則返回False
result = r.set('name', 'test')
print('是否新增成功:', result)
# 獲取,如果鍵存在則返回對應的值,如果鍵不存在則返回None
name = r.get('name')
print('查詢結(jié)果:', name)
# 修改,如果鍵已經(jīng)存在則進?修改,如果鍵不存在則進?添加
result = r.set('name', 'redis')
print('是否修改成功:', result)
name = r.get('name')
print('查詢結(jié)果:', name)
# 獲取所有的鍵
result = r.keys()
print('獲取所有的鍵', result)
# 刪除,刪除鍵及對應的值,如果刪除成功則返回受影響的鍵數(shù),否則則返 回0
result = r.delete('name')
print('刪除key的數(shù)量:', result)
except Exception as e:
print(e)字符串操作
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 設置鍵值對,鍵為'foo',值為'bar'
r.set('foo', 'bar')
# 獲取鍵對應的值
value = r.get('foo')
print(value) # 輸出 b'bar'
# 批量設置鍵值對
r.mset({'apple': 'red', 'banana': 'yellow'})
# 批量獲取鍵對應的值
values = r.mget(['apple', 'banana'])
print(values) # 輸出 [b'red', b'yellow']
# 獲取部分值
part_value = r.getrange('foo', 0, 1)
print(part_value) # 輸出 b'ba'
# 追加字符串
r.append('foo', 'baz')
append_value = r.get('foo')
print(append_value) # 輸出 b'barbaz'
# 自增計數(shù)器
r.incr('counter')
# 獲取計數(shù)器的值
value = r.get('counter')
print(value) # 輸出 b'1'
# 在自增計數(shù)器的基礎上再加上5
r.incrby('counter', 5)
# 獲取計數(shù)器的值
value = r.get('counter')
print(value) # 輸出 b'6'
# 減少計數(shù)器
r.decr('counter')
# 獲取計數(shù)器的值
value = r.get('counter')
print(value) # 輸出 b'5'哈希操作
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 設置哈希表鍵值對
r.hset('user1', 'name', 'Alice')
r.hset('user1', 'age', 20)
r.hset('user1', 'gender', 'female')
# 獲取整個哈希表
hash_table = r.hgetall('user1')
print(hash_table) # 輸出 {b'name': b'Alice', b'age': b'20', b'gender': b'female'}
# 獲取特定鍵對應的值
value = r.hget('user1', 'name')
print(value) # 輸出 b'Alice'
# 刪除哈希表的一個鍵值對
r.hdel('user1', 'gender')
# 獲取所有鍵名
keys = r.hkeys('user1')
print(keys) # 輸出 [b'name', b'age']
# 獲取所有鍵名對應的值
values = r.hvals('user1')
print(values) # 輸出 [b'Alice', b'20']
# 批量設置哈希表鍵值對
r.hmset('user2', {'name': 'Bob', 'age': 25})
# 批量獲取哈希表鍵名對應的值
values = r.hmget('user2', ['name', 'age'])
print(values) # 輸出 [b'Bob', b'25']列表操作
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 從左側(cè)插入元素
r.lpush('mylist1', 'foo')
r.lpush('mylist1', 'bar')
r.lpush('mylist1', 'baz')
# 從右側(cè)刪除元素
r.rpop('mylist1')
# 獲取列表長度
length = r.llen('mylist1')
print(length) # 輸出 2
# 獲取整個列表
mylist = r.lrange('mylist1', 0, -1)
print(mylist) # 輸出 [b'baz', b'bar']
# 從左側(cè)插入元素
r.lpush('mylist2', 'one')
r.lpush('mylist2', 'two')
r.lpush('mylist2', 'three')
# 彈出列表頭部元素
value1 = r.lpop('mylist2')
print(value1) # 輸出 b'three'
# 彈出列表尾部元素
value2 = r.rpop('mylist2')
print(value2) # 輸出 b'one'
# 在指定元素前或后插入新元素
r.linsert('mylist2', 'BEFORE', 'two', 'new')
mylist = r.lrange('mylist2', 0, -1)
print(mylist) # 輸出 [b'new', b'two']
# 裁剪列表
r.ltrim('mylist2', 0, 0)
mylist = r.lrange('mylist2', 0, -1)
print(mylist) # 輸出 [b'new']集合操作
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 向集合中添加元素
r.sadd('set1', 'foo')
r.sadd('set1', 'bar')
# 獲取集合中的所有元素
members = r.smembers('set1')
print(members) # 輸出 {b'foo', b'bar'}
# 獲取集合中的元素數(shù)量
count = r.scard('set1')
print(count) # 輸出 2
# 判斷一個元素是否在集合中
result = r.sismember('set1', 'foo')
print(result) # 輸出 True
# 刪除集合中的一個元素
r.srem('set1', 'bar')
# 獲取多個集合的交集
r.sadd('set2', 'foo')
r.sadd('set2', 'baz')
intersection = r.sinter(['set1', 'set2'])
print(intersection) # 輸出 {b'foo'}
# 獲取多個集合的并集
union = r.sunion(['set1', 'set2'])
print(union) # 輸出 {b'foo', b'baz'}
# 獲取一個集合與多個集合的差集
difference = r.sdiff('set2', ['set1'])
print(difference) # 輸出 {b'baz'}有序集合操作
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 添加有序集合成員和分值
r.zadd('zset1', {'foo': 1.0, 'bar': 2.0, 'baz': 4.0})
# 獲取有序集合的成員數(shù)
count = r.zcard('zset1')
print(count) # 輸出 3
# 獲取有序集合指定范圍內(nèi)的成員
members = r.zrange('zset1', 0, -1)
print(members) # 輸出 [b'foo', b'bar', b'baz']
# 獲取有序集合指定成員的分值
score = r.zscore('zset1', 'bar')
print(score) # 輸出 2.0
# 獲取有序集合指定范圍內(nèi)成員的數(shù)量
count = r.zcount('zset1', 1.5, 3.5)
print(count) # 輸出 1
# 刪除有序集合中一個成員
r.zrem('zset1', 'bar')
# 獲取有序集合中指定范圍內(nèi)的成員和分值
with_scores = r.zrangebyscore('zset1', 0, 5, withscores=True)
print(with_scores) # 輸出 [(b'foo', 1.0), (b'baz', 4.0)]高級用法
Redis管道pipeline
在Redis中,管道(pipeline)是指可以將多個Redis命令依次發(fā)送給Redis,讓Redis 一次性執(zhí)行這些命令并返回結(jié)果的機制。使用管道可以大大減少客戶端與Redis的網(wǎng)絡通信次數(shù),提高Redis的處理效率,是優(yōu)化Redis性能的重要手段之一。
在redis-py庫中,可以使用pipeline()方法創(chuàng)建一個管道對象,并對該對象連續(xù)調(diào)用多個 Redis 命令并提交到 Redis 進行執(zhí)行。提交執(zhí)行后,每個命令都會獲取到這些命令的執(zhí)行結(jié)果,并按照請求的順序返回給客戶端。
特點:
1.可以一次性發(fā)送多條命令并在執(zhí)行完后一次性將結(jié)果返回
2.pipeline通過減少客戶端與Redis的通信次數(shù)來實現(xiàn)降低往返延時時間
實現(xiàn)原理:
- 管道pipeline實現(xiàn)的原理是隊列,隊列是先進先出,這樣就保證數(shù)據(jù)的順序性
- Client可以將三個命令放到一個tcp報文一起發(fā)送
- Server則可以將三條命令的處理結(jié)果放到一個tcp報文返回
基本使用
1.使用 pipeline() 方法創(chuàng)建一個新的 Pipeline 對象,并向該管道對象連續(xù)調(diào)用了三個不同的 SET 命令,分別設置了三個不同的鍵名和對應的鍵值
2.通過 execute() 方法提交管道內(nèi)所有的命令。Redis 服務器一次性執(zhí)行管道內(nèi)所有的命令,并將結(jié)果返回給客戶端
3.最后輸出Redis 管道執(zhí)行的結(jié)果到控制臺,其中包含了每個 SET 命令的執(zhí)行結(jié)果
import redis
# 連接到本地 Redis 服務器,默認端口為 6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 使用 Redis 管道
pipe = r.pipeline()
# 連續(xù)設置多個鍵名和鍵值
pipe.set('name', 'John')
pipe.set('age', 30)
pipe.set('city', 'New York')
# 執(zhí)行 Redis 管道中所有命令,并獲取所有命令的執(zhí)行結(jié)果
result = pipe.execute()
# 輸出 Redis 管道執(zhí)行結(jié)果
print(result)Redis事務
事務 Redis 通過 MULTI 和 EXEC 來實現(xiàn)事務,MULTI 開啟一個事務,EXEC 提交多個命令到 Redis 執(zhí)行,可以保證單位時間內(nèi)只有當前請求在訪問 Redis 服務器,其他讀寫操作會等待這個事務結(jié)束后才能進行,從而保證了數(shù)據(jù)一致性。
基本使用
1.創(chuàng)建一個 redis.StrictRedis 實例,并且設置 transaction 參數(shù)為 True,表示開啟 Redis 事務
2.使用 pipeline() 方法創(chuàng)建一個新的 Pipeline 對象,并將其 transaction 參數(shù)設置為 True,表示這個 Pipeline 是用于 Redis 事務的
3.調(diào)用 multi() 方法開啟Redis 事務,之后向兩個不同的鍵名 foo 和 bar 分別設置了不同的字符串值
4.最后通過 execute() 方法提交事務,Redis 將一次性執(zhí)行整個事務并返回每個命令的執(zhí)行結(jié)果
import redis
# 連接到本地 Redis 服務器,默認端口為 6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 使用 Redis 事務
trans = r.pipeline(transaction=True)
# 開啟事務
trans.multi()
# 向兩個鍵名分別設置不同的值
trans.set('foo', 'hello')
trans.set('bar', 'world')
# 在 Redis 事務中執(zhí)行以上命令,并獲取執(zhí)行結(jié)果
result = trans.execute()
# 輸出 Redis 事務執(zhí)行結(jié)果
print(result)事務與管道的區(qū)別
在Redis中,事務(transaction)和管道(pipeline)都是用于批量執(zhí)行命令的方式,但二者有本質(zhì)上的不同:
1.調(diào)用方式不同
使用事務時,需要先通過MULTI命令將客戶端設置為事務模式,然后按照一定的順序添加執(zhí)行的多個命令,最后通過EXEC命令將操作提交到服務器執(zhí)行。
使用管道時,則是對同一個連接對象上連續(xù)調(diào)用多個Redis命令并且在最后統(tǒng)一執(zhí)行這些命令。
2.發(fā)送機制不同
Redis事務的邏輯單元可以確保所有被包含的命令“原子性”地執(zhí)行,即要么全部執(zhí)行成功完成,要么全部回滾;而Redis>運用管道的方法僅僅是優(yōu)化傳輸,將多個命令打包發(fā)送到Redis服務節(jié)點,并在結(jié)果關(guān)閉時進行收集處理,以達到多個請求一次通信的目的。
3.回滾能力不同
Redis事務提交的過程中如果某個命令執(zhí)行失敗了,后面的命令則都不會再執(zhí)行,已經(jīng)執(zhí)行過的命令不會回滾。當然在EXEC之前可以通過DISCARD命令清空已經(jīng)放入到事務隊列里面的命令;而管道機制暫時沒有回滾的能力。
因此:
Redis管道是解決高性能I/O操作的手段,主要目的在于將多個命令打包,一次發(fā)出去避免了每次發(fā)送都占有一個網(wǎng)絡通道
Redis事務適用于數(shù)據(jù)的批量修改,并期望原子性action。兩種方案各有利弊,需要按照實際業(yè)務場景選擇使用哪一種方式。
分布式鎖
Redis通過 SETNX 和 EXPIRE 等命令實現(xiàn)分布式鎖,可防止多個客戶端同時修改同一資源。具體實現(xiàn)時,檢查一個鍵是否存在,若不存在則對該鍵進行設置并獲得鎖;若已存在則等待。
import time
import uuid
import redis
# 連接到本地 Redis 服務器,默認端口為 6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
def acquire_lock(conn, lockname, acquire_timeout=10, lock_timeout=10):
"""
嘗試獲取鎖,獲取成功返回鎖id;獲取失敗或者異常返回None
:param conn: Redis連接對象
:param lockname: 鎖的名稱
:param acquire_timeout: 最大嘗試獲取鎖的時間(seconds)
:param lock_timeout: 鎖的超時時間(seconds)
:return 是否獲取權(quán)益:鎖的ID/None
"""
identifier = str(uuid.uuid4())
end_time = time.time() + acquire_timeout
while time.time() < end_time:
# 獲取鎖
if conn.setnx(lockname, identifier):
conn.expire(lockname, lock_timeout)
return identifier
# 防止死鎖
elif not conn.ttl(lockname):
conn.expire(lockname, lock_timeout)
time.sleep(0.001)
return None
def release_lock(conn, lockname, identifier):
"""
根據(jù)鎖id釋放鎖,若鎖不存在或者已經(jīng)被其他持有者所釋放則返回False;成功釋放返回True
:param conn: Redis連接對象
:param lockname: 鎖的名稱
:param identifier:鎖的ID
:return 是否釋放:True/False
"""
pipe = conn.pipeline(True)
while True:
try:
# 開啟事務
pipe.watch(lockname)
# 檢查對應鍵是否還是要當前程序設置的值,以avoid誤刪別的客戶端的鎖
if pipe.get(lockname).decode('utf-8') == identifier:
# 刪除鎖
pipe.multi()
pipe.delete(lockname)
pipe.execute()
return True
pipe.unwatch()
break
except redis.exceptions.WatchError:
pass
return False
if __name__ == '__main__':
lockname = " lock"
id = acquire_lock(r, lockname)
print(id)
tag = release_lock(r, lockname, id)
print(tag)訂閱和發(fā)布
Redis 通過 SUBSCRIBE 和 PUBLISH 命令實現(xiàn)類似消息隊列的功能,可以實現(xiàn)多個進程(客戶端)針對一個頻道進行消息的監(jiān)聽和廣播。
import redis
# 連接到本地 Redis 服務器,默認端口為 6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 在 “頻道” 上發(fā)布 “消息”
pub = r.publish('channel', 'Hello World')
# 返回發(fā)布/訂閱對象
sub = r.pubsub()
# 使用此對象,可以訂閱頻道并收聽發(fā)布的消息
sub.subscribe('channel')
for message in sub.listen():
print(message)
print(message['data'])GeoHash
Redis通過GeoHash 實現(xiàn)了地理位置排序和搜索等功能。
import redis
# 連接到本地Redis服務器,默認端口為6379
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 添加地理位置坐標
r.geoadd("locations", 126.6507114792, 45.7603340486, "Harbin")
r.geoadd("locations", 117.2028132333, 39.0879960175, "Beijing")
r.geoadd("locations", 121.5670484719, 38.9544883509, "Tianjin")
# 獲取指定兩點間的距離(以 km 為單位)
distance = r.geodist("locations", "Harbin", "Beijing", unit="km")
print(distance) # 1072.1429
# 搜索指定范圍內(nèi)的地理位置(以 km 為單位),并按照距離從近到遠排序
locations = r.georadiusbymember("locations", "Tianjin", 500, unit="km", withdist=True, sort="ASC")
print(locations) # [[b'Tianjin', 0.0], [b'Beijing', 377.3833]]redis-py-cluster
redis-py-cluster是Python中用于連接Redis集群的模塊,支持對Redis集群中的所有節(jié)點進行Hash槽分配操作,提供了與redis-py相同的API接口,使用方法類似。
GitHub地址:https://github.com/Grokzen/redis-py-cluster
安裝
pip install redis-py-cluster
基本使用
from rediscluster import RedisCluster
# Redis節(jié)點
startup_nodes = [
{"host": "127.0.0.1", "port": "6379"},
{"host": "127.0.0.1", "port": "7001"},
{"host": "127.0.0.1", "port": "7002"}
]
# 創(chuàng)建RedisCluster對象
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
# 與Redis的基本交互
rc.set("foo", "bar")
value = rc.get("foo")
print(value) # bar
# 哈希操作
rc.hset("user", "name", "Alice")
rc.hset("user", "age", 20)
hash_table = rc.hgetall("user")
print(hash_table) # {'name': 'Alice', 'age': '20'}
# 列表操作
rc.lpush("mylist", "foo")
rc.lpush("mylist", "bar")
rc.lpush("mylist", "baz")
mylist = rc.lrange("mylist", 0, -1)
print(mylist) # ['baz', 'bar', 'foo']
# 刪除鍵
rc.delete("foo")以上就是Python實現(xiàn)操作Redis的高級用法分享的詳細內(nèi)容,更多關(guān)于Python操作Redis的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python數(shù)據(jù)報表之Excel操作模塊用法分析
這篇文章主要介紹了Python數(shù)據(jù)報表之Excel操作模塊用法,結(jié)合實例形式分析了XlsxWriter模塊的功能及簡單使用方法,需要的朋友可以參考下2019-03-03
Python+Mysql實現(xiàn)登錄注冊完整代碼示例
在開發(fā)中用戶注冊和登錄是常見的功能需求,這篇文章主要給大家介紹了關(guān)于Python+Mysql實現(xiàn)登錄注冊的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-03-03

