1. 程式人生 > 資料庫 >python3 操作redis

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'))