文章目录
python操作redis
Python操作Redis之普通连接
1. 下载模块
pip install redis
2. 简单使用
from redis import Redis
conn = Redis() # 默认链接本地端口号为6379的redis数据库
ret = conn.set('name', 'UPythonFish') # 设置一个值,name=UPythonFish
print(ret) # 设置成功返回true
Python操作Redis之连接池
# redis_Pool
import redis
# 造一个池子,最多能放100个连接
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379, max_connections=100, decode_responses=True)
'''
需要注意的是,由于redis在6.0版本之前是单线程模式,因此POOL必须是单例模式
解决方法有两种:
1. python中的模块就是天然的单例模式,因此只需要将连接池封装成一个模块即可
2. 写成一个类,生成的对象也是单例模式
decode_responses=True : 取出来的数据自动装换为str类型,有连接池的时候需要放在连接池
'''
# redis_con
from redis import Redis
from redis_Pool import POOL
conn = Redis(connection_pool=POOL)
ret = conn.get('name')
print(ret)操作之String操作
python操作之String操作
- set的使用
1.
conn.set('height', '165', nx=True)
conn.set('height1', '175', ex=1)
conn.set('height2', '185', px=1000)
conn.set('height3', '195', xx=True)
'''
ex: 过期时间(秒)
px: 过期时间(毫秒)
nx: 如果设置为True, 只有name不存在时,当前set操作才执行,值存在,就不执行
xx: 如果设置为True, 只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''
2. setnx(self, name: _Key, value: _Value) -> bool: 等同于 set(nx=True)
3. setex(self, name: _Key, time: int | timedelta, value: _Value) -> bool: 等同于set(ex=)
4. psetex(self, name, time_ms, value): 等同于: set(px)
5. mset(self, mapping: Mapping[_Key, _Value]) -> Literal[True]:
# Mapping的意思是把值以字典的形式批量传入
conn.mset({'name1':'11','name3':'dasfd'})
- get的使用
1. get(self, name: _Key) -> _StrType | None: # 放入一个key返回一个值
2. mget(self, keys: _Key | Iterable[_Key], *args: _Key) -> list[_StrType | None]:
# Iterable[_Key] 传入一个可迭代对象,建议是列表类型,一次获取多个值,没有返回None
ret=conn.mget(['name11','name4','name31'])
ret1=conn.mget(('name1','name','name3'))
print(ret, ret1)
# [None, None, None] [b'11', b'UPythonFish', b'dasfd']
3. getset(self, name, value) -> _StrType | None:
# 传入一个name和一个值,若name存在则将其取出来并修改为value,
# 若name不存在在,则返回None并创造一个name,把value传入
4. getrange(self, key, start, end): # 前闭后闭区间
ret = conn.getrange('name', 0, 2)
ret1 = conn.get('name')
print(ret, ret1)
# UPy UPythonFish
5. getbit(self, name: _Key, offset: int) -> int:
# 获取该数据二进制格式指定位置的数字,返回值只有0和1
- 其他操作
incr :用于统计网站访问量,页面访问量,接口访问量
incr(self, name: _Key, amount: int = ...) -> int: ...
conn.incr('name1') # 只要一执行,数字加1,也可以指定参数
conn.incr('name1', 5) # 数字加5
conn.incr('name1', -3) # 数字减3
decr(self, name, amount=...) -> int: 与incr相反
conn.append('name1','oo') # 在字符串后面追加
- 总结
字符串操作重点是:
set、mset、get、mget、incr、decr、append
python操作之Hash操作
# 设置hash数据一次只能设置一组值,若k存在,则修改
hset(self, name: _Key, key: _Key, value: _Value, mapping: Mapping[_Key, _Value] | None = ...) -> int: ...
conn.hset('hash1','name','python') # key不可以重复
# 批量添加键值对
hmset(self, name: _Key, mapping: Mapping[_Key, _Value]) -> bool:
conn.hmset('hash2',{'key1':'value1','key2':'value2'})
# 根据name和key值获取val值 只能取一个
hget(self, name: _Key, key: _Key) -> _StrType | None:
# 根据name和key获取val值,可以同时获取多个key对应的val值,没有返回None
hmget(self, name: _Key, keys: _Key | Iterable[_Key], *args: _Key) -> list[_StrType | None]: ...
# 根据name值获取所有的值,以字典的形式返回 不建议使用
hgetall(self, name: _Key) -> dict[_StrType, _StrType]:
# 根据name获取所有的值,生成一个迭代器,推荐使用
hscan_iter(self, name, match=..., count=...): ...
# 根据key值删除val值,可以放多个
hdel(self, name: _Key, *keys: _Key) -> int: ...
# 判断key值是否存在
hexists(self, name: _Key, key: _Key) -> bool: ...
# val值必须是整数,给表中值+给定值(int类型),可以是负数
hincrby(self, name: _Key, key: _Key, amount: int = ...) -> int:
conn.hincrby('hash1', 'name1',5)
# val值必须是数值类型,给表中值+给定值(int和float类型),可以是负数
hincrbyfloat(self, name: _Key, key: _Key, amount: float = ...) -> float:
# 获取表中所有的key值
hkeys(self, name: _Key) -> list[_StrType]: ...
# 获取表中所有的val值
hvals(self, name: _Key) -> list[_StrType]: ...
# 统计表中key的数量
hlen(self, name: _Key) -> int: ...
# 设置值,只有key不存在时,执行设置操作(添加),如果存在,不会修改
hsetnx(self, name: _Key, key: _Key, value: _Value) -> int: ...
重点掌握
hset、hget、hmset、hmget、hincrby、区分hgetall和hscan_iter
python操作之List操作
# 从左边插入数据,可以是多条,返回值是数据列表长度
lpush(self, name: _Value, *values: _Value) -> int: ...
conn.lpush('list1',1,2,3,4,5)
# 插入一个数据,必须name值存在才能放
lpushx(self, name, value): ...
# 获取name对应的列表的长度
llen(self, name: _Key) -> int: ...
# 在指定值前面或后面插入值
linsert( self, name: _Key, where: Literal["BEFORE", "AFTER", "before", "after"], refvalue: _Value, value: _Value) -> int: ...
# 对name对应的list中的某一个索引位置重新赋值
lset(self, name: _Key, index: int, value: _Value) -> bool: ...
# 删除name对应的list中所指定的值,count指定删除多少
# count=0 全部删除, count=2 从前往后删2个, count=-2 从后往前删2个
lrem(self, name: _Key, count: int, value: _Value) -> int: ...
# 在name对应的列表左侧弹出第一个元素 rpop: 从右侧
lpop(self, name): ...
# 在name对应的列表中根据索引获取列表元素
lindex(self, name: _Key, index: int) -> _StrType | None: ...
# 在name对应的列表分片获取数据[前闭后闭区间]
lrange(self, name: _Key, start: int, end: int) ->list[_StrType]:
# 重点block,阻塞,可以写一个超时时间
# 将多个列表排列,按照从左到后去pop对应列表的元素
# keys: redis的name集合
# timeout: 超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内的数据的时间(秒),0表示永远阻塞
# brpop: 与blpop相反,从右往左获取数据
blpop(self, keys: _Value | Iterable[_Value], timeout: Literal[0] = ...) -> tuple[_StrType, _StrType]:
# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
brpoplpush(self, src, dst, timeout=...): ...
重点掌握
lpush,lpop,blpop,lrange,llen
自定制分批取列表的数据
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
# 使用
for item in scan_list('test', 5):
print(item)
python操作之Set操作
Set操作,Set集合就是不允许重复的列表
sadd(name,values)
name对应的集合中添加元素
scard(name)
获取name对应的集合中元素个数
sdiff(keys, *args)
在第一个name对应的集合中且不在其他name对应的集合的元素集合
sdiffstore(dest, keys, *args)
# 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
sinter(keys, *args)
# 获取多一个name对应集合的并集
sinterstore(dest, keys, *args)
# 获取多一个name对应集合的并集,再讲其加入到dest对应的集合中
sismember(name, value)
# 检查value是否是name对应的集合的成员
smembers(name)
# 获取name对应的集合的所有成员
smove(src, dst, value)
# 将某个成员从一个集合中移动到另外一个集合
spop(name)
# 从集合的右侧(尾部)移除一个成员,并将其返回
srandmember(name, numbers)
# 从name对应的集合中随机获取 numbers 个元素
srem(name, values)
# 在name对应的集合中删除某些值
srem(name, values)
# 在name对应的集合中删除某些值
sunion(keys, *args)
# 获取多一个name对应的集合的并集
sunionstore(dest,keys, *args)
# 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中
sscan(name, cursor=0, match=None, count=None)
sscan_iter(name, match=None, count=None)
# 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
*zadd(name, *args, *kwargs)
# 在name对应的有序集合中添加元素
# 如:
# zadd('zz', 'n1', 1, 'n2', 2)
# 或
# zadd('zz', n1=11, n2=22)
zcard(name)
# 获取name对应的有序集合元素的数量
zcount(name, min, max)
# 获取name对应的有序集合中分数 在 [min,max] 之间的个数
zincrby(name, value, amount)
# 自增name对应的有序集合的 name 对应的分数
r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
# 按照索引范围获取name对应的有序集合的元素
# 参数:
# name,redis的name
# start,有序集合索引起始位置(非分数)
# end,有序集合索引结束位置(非分数)
# desc,排序规则,默认按照分数从小到大排序
# withscores,是否获取元素的分数,默认只获取元素的值
# score_cast_func,对分数进行数据转换的函数
# 更多:
# 从大到小排序
# zrevrange(name, start, end, withscores=False, score_cast_func=float)
# 按照分数范围获取name对应的有序集合的元素
# zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)
# 从大到小排序
# zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)
zrank(name, value)
# 获取某个值在 name对应的有序集合中的排行(从 0 开始)
# 更多:
# zrevrank(name, value),从大到小排序
zrangebylex(name, min, max, start=None, num=None)
# 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员
# 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大
# 参数:
# name,redis的name
# min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
# min,右区间(值)
# start,对结果进行分片处理,索引位置
# num,对结果进行分片处理,索引后面的num个元素
# 如:
# ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
# r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']
# 更多:
# 从大到小排序
# zrevrangebylex(name, max, min, start=None, num=None)
zrem(name, values)
# 删除name对应的有序集合中值是values的成员
# 如:zrem('zz', ['s1', 's2'])
zremrangebyrank(name, min, max)
# 根据排行范围删除
zremrangebyscore(name, min, max)
# 根据分数范围删除
zremrangebylex(name, min, max)
# 根据值返回删除
zscore(name, value)
# 获取name对应有序集合中 value 对应的分数
zinterstore(dest, keys, aggregate=None)
# 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
zunionstore(dest, keys, aggregate=None)
# 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
zscan_iter(name, match=None, count=None,score_cast_func=float)
# 同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作
redis的其他操作
delete(*names)
# 根据删除redis中的任意数据类型
exists(name)
# 检测redis的name是否存在
keys(pattern=’*’)
# 根据模型获取redis的name
# 更多:
# KEYS * 匹配数据库中所有 key 。
# KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
# KEYS h*llo 匹配 hllo 和 heeeeello 等。
# KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
expire(name ,time)
# 为某个redis的某个name设置超时时间
rename(src, dst)
# 对redis的name重命名为
move(name, db))
# 将redis的某个值移动到指定的db下
randomkey()
# 随机获取一个redis的name(不删除)
type(name)
# 获取name对应值的类型
scan(cursor=0, match=None, count=None)
scan_iter(match=None, count=None)
# 同字符串操作,用于增量迭代获取key
管道
redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。
redis的事物也是基于这一特性而实现的
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
conn = redis.Redis(connection_pool=pool)
pipe = conn.pipeline(transaction=True)
pipe.multi()
pipe.set('name', 'python')
pipe.set('role', 'tom')
pipe.execute() # redis才开始去执行命令
Django中使用redis
方式1(通用方式):
utils文件夹下,建立redis_pool.py
import redis
POOL = redis.ConnectionPool(host='127.0.0.1',port=6379,password='1234',max_connections=1000)
然后在视图函数中使用
方式二:
安装django-redis模块
pip install django-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",
}
}
}
视图函数中使用:
1 使用cache
from django.core.cache import cache
cache.set('name',user)
2 直接使用
from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))