python3 操作redis
安裝和使用
安裝
安裝redis模組
pip3 install redis
普通連線
redis-py提供兩個類Redis和StrictRedis用於實現Redis的命令,StrictRedis用於實現大部分官方的命令,並使用官方的語法和命令,Redis是StrictRedis的子類,用於向後相容舊版本的redis-py
import redis conn = redis.Redis(host='127.0.0.1',port=6379) # 可以使用url方式連線到資料庫 # conn = Redis.from_url('redis://@localhost:6379/1') conn.set('name','LinWOW') print(conn.get('name'))
連線池
redis-py使用connection pool來管理對一個redis server的所有連線,避免每次建立、釋放連線的開銷。預設,每個Redis例項都會維護一個自己的連線池。可以直接建立一個連線池,然後作為引數Redis,這樣就可以實現多個Redis例項共享一個連線池
連線池:redis_pool.py
from redis import ConnectionPool
POOL=ConnectionPool(host='127.0.0.1',port=6379,max_connections=100)
使用連線池:test_redis.py
import redis from redis_pool import POOl conn = redis.Redis(connection_pool=POOl) conn.set('name','LinWOW') print(conn.get('name'))
構造url方式連線到資料庫,有以下三種模式:
redis://[:password]@host:port/db # TCP連線
rediss://[:password]@host:port/db # Redis TCP+SSL 連線
unix://[:password]@/path/to/socket.sock?db=db # Redis Unix Socket 連線
Python操作Redis
String操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
set(name,value,ex=None,px=None,nx=False,xx=False) | ex,過期時間(s);px,過期時間(ms);nx,如果設定為True,則只有name不存在時,當前set操作才執行,值存在,就修改不了,執行沒效果;xx,如果設定為True,則只有name存在時,當前set操作才執行,值存在才能修改,值不存在,不會設定新值 | 效果和setex,setnx一致 | |
set(name,value) | 給name賦值為value | redis.set(‘name’,‘Bob’) | True |
get(name) | 返回資料庫中key為name的string的value | redis.get(‘name’) | b’Bob’ |
getset(name,value) | 給資料庫中key為name的string賦予值value並返回上次的value | redis.getset(‘name’,‘Mike’) | b’Bob’ |
mget(keys,*args) | 返回多個key對應的value | redis.mget([‘name’,‘nickname’]) | [b’Mike’,b’Miker’] |
setnx(name,value) | 如果key不存在才設定value | redis.setnx(‘newname’,‘James’) | 第一次執行True,第二次False |
setex(name,time,value) | 設定可以對應的值為string型別的value,並指定此鍵值對應的有效期 | redis.setex(‘name’,1,‘James’) | True |
setrange(name,offset,value) | 設定指定key的value值的子字串 | redis.set(‘name’,‘Hello’) redis.setrange(‘name’,6,‘World’) | 11,修改後的字串長度 |
mset(mapping) | 批量賦值 | redis.mset({‘name1’: ‘Durant’,‘name2’: ‘James’}) | True |
msetnx(mapping) | key均不存在時才批量賦值 | redis.msetnx({‘name3’: ‘Smith’,‘name4’: ‘Curry’}) | True |
incr(name,amount=1) | key為name的value增值操作,預設1,key不存在則被建立並設為amount | redis.incr(‘age’,1) | 1,即修改後的值 |
decr(name,amount=1) | key為name的value減值操作,預設1,key不存在則被建立並設定為-amount | redis.decr(‘age’,1) | -1,即修改後的值 |
append(key,value) | key為name的string的值附加value | redis.append(‘nickname’,‘OK’) | 13,即修改後的字串長度 |
substr(name,start,end=-1) | 返回key為name的string的value的子串 | redis.substr(‘name’,4) | b’ello’ |
getrange(key,end) | 獲取key的value值從start到end的子字串 | redis.getrange(‘name’,4) | b’ello’ |
Key操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
exists(name) | 判斷一個key是否存在 | redis.exists(‘name’) | True |
delete(name) | 刪除一個key | redis.delete(‘name’) | 1 |
type(name) | 判斷key型別 | redis.type(‘name’) | b’string’ |
keys(pattern) | 獲取所有符合規則的key | redis.keys(‘n*’) | [b’name’] |
randomkey() | 獲取隨機的一個key | randomkey() | b’name’ |
rename(src,dst) | 將key重新命名 | redis.rename(‘name’,‘nickname’) | True |
dbsize() | 獲取當前資料庫中key的數目 | dbsize() | 100 |
expire(name,time) | 設定key的過期時間,單位秒 | redis.expire(‘name’,2) | True |
ttl(name) | 獲取key的過期時間,單位秒,-1為永久不過期 | redis.ttl(‘name’) | -1 |
move(name,db) | 將key移動到其他資料庫 | move(‘name’,2) | True |
flushdb() | 刪除當前選擇資料庫中的所有key | flushdb() | True |
flushall() | 刪除所有資料庫中的所有key | flushall() | True |
List操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
rpush(name,*values) | 在key為name的list尾新增值為value的元素,可以傳多個 | redis.rpush(‘list’,2,3) | 3,list大小 |
lpush(name,*values) | 在key為name的list頭新增值為value的元素,可以傳多個 | redis.lpush(‘list’,0) | 4,list大小 |
llen(name) | 返回key為name的list的長度 | redis.llen(‘list’) | 4 |
lrange(name,end) | 返回key為name的list中start至end之間的元素 | redis.lrange(‘list’,3) | [b’3’,b’2’,b’1’] |
ltrim(name,end) | 擷取key為name的list,保留索引為start到end的內容 | ltrim(‘list’,3) | True |
lindex(name,index) | 返回key為name的list中index位置的元素 | redis.lindex(‘list’,1) | b’2’ |
lset(name,index,value) | 給key為name的list中index位置的元素賦值,越界則報錯 | redis.lset(‘list’,5) | True |
lrem(name,count,value) | 刪除count個key的list中值為value的元素 | redis.lrem(‘list’,3) | 1,即刪除的個數 |
lpop(name) | 返回並刪除key為name的list中的首元素 | redis.lpop(‘list’) | b’5’ |
rpop(name) | 返回並刪除key為name的list中的尾元素 | redis.rpop(‘list’) | b’2’ |
blpop(keys,timeout=0) | 返回並刪除名稱為在keys中的list中的首元素,如果list為空,則會一直阻塞等待 | redis.blpop(‘list’) | [b’5’] |
brpop(keys,timeout=0) | 返回並刪除key為name的list中的尾元素,如果list為空,則會一直阻塞等待 | redis.brpop(‘list’) | [b’2’] |
rpoplpush(src,dst) | 返回並刪除名稱為src的list的尾元素,並將該元素新增到名稱為dst的list的頭部 | redis.rpoplpush(‘list’,‘list2’) | b’2’ |
應用場景:
blpop實現簡單分散式爬蟲:
多個url放到列表裡,往裡不停放URL,程式迴圈取值,但是隻能一臺機器執行取值,可以把url放到redis中,多臺機器從redis中取值,爬取資料,實現簡單分散式
將多個列表排列,按照從左到右去pop對應列表的元素
引數:
keys,redis的name的集合
timeout,超時時間,當元素所有列表的元素獲取完之後,阻塞等待列表內有資料的時間(秒),0 表示永遠阻塞
更多:
r.brpop(keys,timeout),從右向左獲取資料
自定義增量迭代:
由於redis類庫中沒有提供對列表元素的增量迭代,如果想要迴圈name對應的列表的所有元素,那麼就需要:
1、獲取name對應的所有列表
2、迴圈列表
但是,如果列表非常大,那麼就有可能在第一步時就將程式的內容撐爆,所有有必要自定義一個增量迭代的功能:
import redis
conn=redis.Redis(host='127.0.0.1',port=6379)
# conn.lpush('test',*[1,3,4,45,5,7,8,43,768,89,9,65,23,54,6757,68])
# conn.flushall()
def scan_list(name,count=2):
index=0
while True:
data_list=conn.lrange(name,count+index-1)
if not data_list:
return
index+=count
for item in data_list:
yield item
print(conn.lrange('test',100))
for item in scan_list('test',5):
print('---')
print(item)
Set操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
sadd(name,*values) | 向key為name的set中新增元素 | redis.sadd(‘tags’,‘Book’,‘Tea’,‘Coffee’) | 3,即插入的資料個數 |
srem(name,*values) | 從key為name的set中刪除元素 | redis.srem(‘tags’,‘Book’) | 1,即刪除的資料個數 |
spop(name) | 隨機返回並刪除key為name的set中一個元素 | redis.spop(‘tags’) | b’Tea’ |
smove(src,dst,value) | 從src對應的set中移除元素並新增到dst對應的set中 | redis.smove(‘tags’,‘tags2’,‘Coffee’) | True |
scard(name) | 返回key為name的set的元素個數 | redis.scard(‘tags’) | 3 |
sismember(name,value) | 測試member是否是key為name的set的元素 | redis.sismember(‘tags’,‘Book’) | True |
sinter(keys,*args) | 返回所有給定key的set的交集 | redis.sinter([‘tags’,‘tags2’]) | {b’Coffee’} |
sinterstore(dest,keys,*args) | 求交集並將交集儲存到dest的集合 | redis.sinterstore(‘inttag’,[‘tags’,‘tags2’]) | 1 |
sunion(keys,*args) | 返回所有給定key的set的並集 | redis.sunion([‘tags’,‘tags2’]) | {b’Coffee’,b’Book’,b’Pen’} |
sunionstore(dest,*args) | 求並集並將並集儲存到dest的集合 | redis.sunionstore(‘inttag’,‘tags2’]) | 3 |
sdiff(keys,*args) | 返回所有給定key的set的差集 | redis.sdiff([‘tags’,‘tags2’]) | {b’Book’,b’Pen’} |
sdiffstore(dest,*args) | 求差集並將差集儲存到dest的集合 | redis.sdiffstore(‘inttag’,‘tags2’]) | 3 |
smembers(name) | 返回key為name的set的所有元素 | redis.smembers(‘tags’) | {b’Pen’,b’Coffee’} |
srandmember(name) | 隨機返回key為name的set的一個元素,但不刪除元素 | redis.srandmember(‘tags’) |
Sorted Set操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
zadd(name,args,*kwargs) | 向key為name的zset中新增元素member,score用於排序。如果該元素存在,則更新其順序 | redis.zadd(‘grade’,100,‘Bob’,98,‘Mike’) | 2,即新增的元素個數 |
zrem(name,*values) | 刪除key為name的zset中的元素 | redis.zrem(‘grade’,‘Mike’) | 1,即刪除的元素個數 |
zincrby(name,amount=1) | 如果在key為name的zset中已經存在元素value,則該元素的score增加amount,否則向該集合中新增該元素,其score的值為amount | redis.zincrby(‘grade’,-2) | 98.0,即修改後的值 |
zrank(name,value) | 返回key為name的zset中元素的排名(按score從小到大排序)即下標 | redis.zrank(‘grade’,‘Amy’) | 1 |
zrevrank(name,value) | 返回key為name的zset中元素的倒數排名(按score從大到小排序)即下標 | redis.zrevrank(‘grade’,‘Amy’) | 2 |
zrevrange(name,end,withscores=False) | 返回key為name的zset(按score從大到小排序)中的index從start到end的所有元素 | redis.zrevrange(‘grade’,3) | [b’Bob’,b’Mike’,b’Amy’,b’James’] |
zrangebyscore(name,min,max,start=None,num=None,withscores=False) | 返回key為name的zset中score在給定區間的元素 | redis.zrangebyscore(‘grade’,80,95) | [b’Amy’,b’James’] |
zcount(name,max) | 返回key為name的zset中score在給定區間的數量 | redis.zcount(‘grade’,95) | 2 |
zcard(name) | 返回key為name的zset的元素個數 | redis.zcard(‘grade’) | 3 |
zremrangebyrank(name,max) | 刪除key為name的zset中排名在給定區間的元素 | redis.zremrangebyrank(‘grade’,0) | 1,即刪除的元素個數 |
zremrangebyscore(name,max) | 刪除key為name的zset中score在給定區間的元素 | redis.zremrangebyscore(‘grade’,90) | 1,即刪除的元素個數 |
Hash操作
方法 | 作用 | 示例 | 示例結果 |
---|---|---|---|
hset(name,key,value) | 向key為name的hash中新增對映 | hset(‘price’,‘cake’,5) | 1,即新增的對映個數 |
hsetnx(name,value) | 向key為name的hash中新增對映,如果對映鍵名不存在 | hsetnx(‘price’,‘book’,6) | 1,即新增的對映個數 |
hget(name,key) | 返回key為name的hash中field對應的value | redis.hget(‘price’,‘cake’) | 5 |
hmget(name,*args) | 返回key為name的hash中各個鍵對應的value | redis.hmget(‘price’,[‘apple’,‘orange’]) | [b’3’,b’7’] |
hmset(name,mapping) | 向key為name的hash中批量新增對映 | redis.hmset(‘price’,{‘banana’: 2,‘pear’: 6}) | True |
hincrby(name,amount=1) | 將key為name的hash中對映的value增加amount | redis.hincrby(‘price’,‘apple’,3) | 6,修改後的值 |
hexists(name,key) | key為namehash中是否存在鍵名為key的對映 | redis.hexists(‘price’,‘banana’) | True |
hdel(name,*keys) | key為namehash中刪除鍵名為key的對映 | redis.hdel(‘price’,‘banana’) | True |
hlen(name) | 從key為name的hash中獲取對映個數 | redis.hlen(‘price’) | 6 |
hkeys(name) | 從key為name的hash中獲取所有對映鍵名 | redis.hkeys(‘price’) | [b’cake’,b’book’,b’banana’,b’pear’] |
hvals(name) | 從key為name的hash中獲取所有對映鍵值 | redis.hvals(‘price’) | [b’5’,b’6’,b’6’] |
hgetall(name) | 從key為name的hash中獲取所有對映鍵值對 | redis.hgetall(‘price’) | {b’cake’: b’5’,b’book’: b’6’,b’orange’: b’7’,b’pear’: b’6’} |
注意點:
hscan(name,cursor=0,match=None,count=None):增量式迭代獲取,對於資料大的資料非常有用,hscan可以實現分片的獲取資料,並非一次性將資料全部獲取完,從而放置記憶體被撐爆
引數:
name,redis的name
cursor,遊標(基於遊標分批取獲取資料)
match,匹配指定key,預設None 表示所有的key
count,每次分片最少獲取個數,預設None表示採用Redis的預設分片個數
如:
第一次:cursor1,data1 = r.hscan('xx',count=None)
第二次:cursor2,cursor=cursor1,count=None)
...
直到返回值cursor的值為0時,表示資料已經通過分片獲取完畢
hscan_iter(name,count=None): 利用yield封裝hscan建立生成器,實現分批去redis中獲取資料
引數:
match,匹配指定key,預設None 表示所有的key
count,每次分片最少獲取個數,預設None表示採用Redis的預設分片個數
如:
for item in r.hscan_iter('xx'):
print item
管道
redis-py預設在執行每次請求都會建立(連線池申請連線)和斷開(歸還連線池)一次連線操作,如果想要在一次請求中指定多個命令,則可以使用pipline實現一次請求指定多個命令,並且預設情況下一次pipline 是原子性操作。
import redis
pool = redis.ConnectionPool(host='10.211.55.4',port=6379)
r = redis.Redis(connection_pool=pool)
# pipe = r.pipeline(transaction=False)
pipe = r.pipeline(transaction=True)
pipe.multi()
pipe.set('name','linwow')
pipe.set('age','18')
pipe.execute()
Django中使用redis
方式一:
utils資料夾下,建立redis_pool.py
import redis
POOL = redis.ConnectionPool(host='127.0.0.1',password='1234',max_connections=1000)
檢視函式中使用:
import redis
from django.shortcuts import render,HttpResponse
from redis_pool import POOL
def index(request):
conn = redis.Redis(connection_pool=POOL)
conn.hset('liwow','age',18)
return HttpResponse('設定成功')
def order(request):
conn = redis.Redis(connection_pool=POOL)
conn.hget('kkk','age')
return HttpResponse('獲取成功')
方式二:
安裝django-redis模組
pip3 install django-redis
setting裡配置:
# redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379","OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient","CONNECTION_POOL_KWARGS": {"max_connections": 100}
# "PASSWORD": "123",}
}
}
檢視函式:
from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))