一、Redis
Redis 是一個 key-value 的存儲系統,和Memcached類似,value 有五大數據類型,並且數據都是緩存在內存中。
- string(字符串)
- list(鏈表)
- set(集合)
- zset(有序集合)
- hash(哈希類型)
Redis 的好處特點
好處:
- 速度快:因為數據存儲在內存中。
- 有豐富的數據類型:五大數據類型。
- 支持事物:操作都是原子性,也就是說要么都成功,要么都失敗。
- 豐富的特性:可用於緩存,消息,按 key 設置過期時間,過期后自動刪除。
特點:
- 可以持久化
- 單線程、單進程
與Memcached比較
- Memcached 只支持一種數據類型字符串
- Memcached 不支持持久化(不支持存到硬盤上,只要一斷電,數據就沒了)
二、python 操作 Redis
普通連接
from redis import Redis
# 簡單使用
conn = Redis(host='127.0.0.1', port=6379)
ret = conn.get('name') # 取出
print(ret)
# 輸出
b'xiaoyang'
Redis連接池
為了避免每次建立,釋放連接的開銷,所以就需要建立一個連接池,每次都從連接池中拿連接操作
由於 POOL 必須是單例的,每次拿都是拿原來那個池子里的,所以 POOL 要寫成一個模塊
redis_pool.py
import redis
# 生成一個池子對象最多能放100個連接
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=100)
test.py
from redis import Redis
from redis_pool import POOL
conn = Redis(connection_pool=POOL) # 只要執行這句話,就是從池中拿出一個連接
ret = conn.get('name')
print(ret)
# 輸出
b'xiaoyang'
常用String 操作
set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中設置值,默認,不存在則創建,存在則修改
參數:
ex,過期時間(秒)
px,過期時間(毫秒)
nx,如果設置為True,則只有name不存在時,當前set操作才執行,值存在,就修改不了,執行沒效果
xx,如果設置為True,則只有name存在時,當前set操作才執行,值存在才能修改,值不存在,不會設置新值
mset(*args, **kwargs)
批量設置值
如:
mset(k1='v1', k2='v2')
或
mget({'k1': 'v1', 'k2': 'v2'})
get(name)
獲取值
mget(keys, *args)
批量獲取
如:
mget('k1', 'k2')
或
r.mget(['k3', 'k4'])
getset(name, value)
設置新值並獲取原來的值
bitop(operation, dest, *keys)
獲取多個值,並將值做位運算,將最后的結果保存至新的name對應的值
參數:
operation,AND(並) 、 OR(或) 、 NOT(非) 、 XOR(異或)
dest, 新的Redis的name
*keys,要查找的Redis的name
# 如:獲取Redis中n1,n2,n3對應的值,然后講所有的值做位運算(求並集),然后將結果保存 new_name 對應的值中
bitop("AND", 'new_name', 'n1', 'n2', 'n3')
strlen(name)
返回name對應值的字節長度(一個漢字3個字節)
incr(self, name, amount=1)
自增 name對應的值,當name不存在時,則創建name=amount,否則,則自增。
參數:
name,Redis的name
amount,自增數(必須是整數)
注:
同incrby
incrbyfloat 自增浮點型
decr(self, name, amount=1)
自減 name對應的值,當name不存在時,則創建name=amount,否則,則自減。
參數:
name,Redis的name
amount,自減數(整數)
append(key, value)
在redis name對應的值后面追加內容
參數:
key, redis的name
value, 要追加的字符串
常用Hash操作
hset(name, key, value)
name對應的hash中設置一個鍵值對(不存在,則創建;否則,修改)
參數:
name,redis的name
key,name對應的hash中的key
value,name對應的hash中的value
注:
hsetnx(name, key, value),當name對應的hash中不存在當前key時則創建(相當於添加)
hmset(name, mapping)
在name對應的hash中批量設置鍵值對
參數:
name,redis的name
mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
如:
conn.hmset('xx', {'k1':'v1', 'k2': 'v2'})
hget(name,key)
在name對應的hash中獲取根據key獲取value
hmget(name, keys, *args)
在name對應的hash中獲取多個key的值
參數:
name,reids對應的name
keys,要獲取key集合,如:['k1', 'k2', 'k3']
*args,要獲取的key,如:k1,k2,k3
如:
r.mget('xx', ['k1', 'k2'])
或
print r.hmget('xx', 'k1', 'k2')
hgetall(name)——少用
獲取name對應hash的所有鍵值
hscan_iter(name, match=None, count=None)
利用yield封裝hscan創建生成器,實現分批去redis中獲取數據
參數:
match,匹配指定key,默認None 表示所有的key
count,每次分片最少獲取個數,默認None表示采用Redis的默認分片個數
如:
for item in r.hscan_iter('xx'):
print item
hincrby(name, key, amount=1)
自增name對應的hash中的指定key的值,不存在則創建key=amount
參數:
name,redis中的name
key, hash對應的key
amount,自增數(整數)
注:
hincrbyfloat(name, key, amount=1.0) 自增浮點型
hlen(name):獲取 name 對應的hash中鍵值對的個數
hkeys(name):獲取 name 對應的 hash 中所有的 key 的值
hvals(name):獲取 name 對應的 hash 中所有的 value 的值
hexists(name, key):檢查 name 對應的 hash 是否存在當前傳入的 key
hdel(name,*keys):將 name 對應的 hash 中指定 key 的鍵值對刪除
常用List操作
lpush(name,values)
在name對應的list中添加元素,每個新的元素都添加到列表的最左邊
如:
conn.lpush('oo', 11,22,33)
保存順序為: 33,22,11
擴展:
rpush(name, values) 表示從右向左操作
lpushx(name,value)
在name對應的list中添加元素,只有name已經存在時,值添加到列表的最左邊
更多:
rpushx(name, value) 表示從右向左操作
lpop(name)
在name對應的列表的左側獲取第一個元素並在列表中移除,返回值則是第一個元素
更多:
rpop(name) 表示從右向左操作
blpop(keys, timeout)
將多個列表排列,按照從左到右去pop對應列表的元素
參數:
keys,redis的name的集合
timeout,超時時間,當元素所有列表的元素獲取完之后,阻塞等待列表內有數據的時間(秒), 0 表示永遠阻塞
lrange(name, start, end)
在name對應的列表分片獲取數據
參數:
name,redis的name
start,索引的起始位置
end,索引結束位置
llen(name)
name對應的list元素的個數
lrem(name, value, num)
在name對應的list中刪除指定的值
參數:
name, redis的name
value, 要刪除的值
num, num=0,刪除列表中所有的指定值;
num=2,從前到后,刪除2個;
num=-2,從后向前,刪除2個
自定義增量迭代
由於redis類庫中沒有提供對列表元素的增量迭代,如果想要循環name對應的列表的所有元素,那么就需要:
- 獲取name對應的所有列表
- 循環列表
但是,如果列表非常大,那么就有可能在第一步時就將程序的內容撐爆,所有有必要自定義一個增量迭代的功能:
def scan_list(name,count=2):
index=0
while True:
data_list=conn.lrange(name,index,count+index-1)
if not data_list:
return
index+=count
for item in data_list:
yield item # 只有拿完了才會去下一次while循環
print(conn.lrange('test',0,100))
for item in scan_list('test',5):
print(item)
通用操作
keys(pattern='*')
根據模型獲取 redis 的 name ——> 模糊匹配
更多:
KEYS * 匹配數據庫中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS h*llo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
delete(*names):根據 name 刪除 Redis 中的任意數據類型
exists(name):檢測 Redis 的 name 是否存在
expire(name ,time):為某個 redis 的某個 name 設置超時時間
rename(src, dst):重命名
move(name, db):將redis的某個值移動到指定的db下
randomkey():隨機獲取一個redis的name(不刪除)
type(name):獲取name對應值的類型
管道
Redis 支持事務,但是是使用管道實現事務的,要么都成功,要么都失敗。
redis_pool.py
import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=100)
使用:
from redis import Redis
from redis_pool import POOL
conn = Redis(connection_pool=POOL)
pipe = conn.pipeline(transaction=True) # 開啟事務
pipe.multi()
pipe.set('name', 'xiaoyang')
pipe.set('age', '20')
pipe.execute() # 執行這句話才會真正去執行
三、Django中使用Redis
方式一:通用方式
建立redis_pool.py
import redis
# 生成一個池子對象最多能放100個連接
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=100)
視圖函數中使用:
import redis
from django.shortcuts import render,HttpResponse
from redis_pool import POOL
def index(request):
conn = redis.Redis(connection_pool=POOL)
conn.hset('xiaoyang','name','xiaoyang')
return HttpResponse('設置成功')
def order(request):
conn = redis.Redis(connection_pool=POOL)
conn.hget('xiaoyang','name')
return HttpResponse('獲取成功')
方式二:django-redis
在 setting 中配置:
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": "123456", # 密碼
}
}
}
使用方式一:使用cache
from django.core.cache import cache
cache.set('name', 'xiaoyang')
使用方式二:直接使用conn對象
from django_redis import get_redis_connection
conn = get_redis_connection('default')
conn.set('name', 'xiaoyang')
ret = conn.get('name')
print(ret)