对于Redis的相应原理以及知识点对应的java版本,可看我之前的文章:(其知识点都是互通的)
Redis框架从入门到学精(全)
对于以上的前置知识如果了解了更好,如果不了解,就当是一种数据库,上手也很快。
本身Redis就是一种可持久的Key-Value的数据库,有丰富的数据结构等
通过pip install redis
进行安装导入redis的模块包即可
如果在安装以及使用的过程中遇到这些bug
可看我之前的文章:
本身就是一种数据库,操作数据库第一就是连接Redis,本身有两个类可以连接,官方提供了Redis(StrictRedis的子类)以及StrictRedis。
连接也有两种方式:
第一种方式是正常连接:
# 导入redis的包
import redis
# 通过redis连接用户名、端口、密码以及db数据库
redis_conn = redis.Redis(host='127.0.0.1', port= 6379, password= '?', db= 0,decode_responses=True)
redis_conn = redis.StrictRedis(host='127.0.0.1', port= 6379, password= '?', db= 0,decode_responses=True)
关于以上的连接参数中:
decode_responses=True输出的时候变为字符串,默认输出是字节(decode_responses可不用)
连接方式的第二种是:(使用连接池)
连接池的好处是通过连接池来管理其所有的连接,避免对建立释放连接等开销
import redis
redis_pool = redis.ConnectionPool(host='127.0.0.1', port= 6379, password= '?', db= 0)
# 通过调用连接池
redis_conn = redis.Redis(connection_pool= redis_pool)
在基本类型中介绍其方法的使用
正常连接之后 大部分都可通过如下查看其共性的东西:
通过set设置键值对:redis.set('manong',18)
获取键值:redis.get('manong')
判断键值是否存在:redis.exists('manong')
查看键值的类型:redis.type('manong')
获取当前数据库中键值对数目:redis.dbsize()
以及其他的函数,可参照官网进行学习
基本的使用类型以及方法会用即可
其实Sting类在上面的展示中已经有使用到
函数:
描述 | 函数用法 |
---|---|
设置单个键值对 | set(name, value, ex=None, px=None, nx=False, xx=False, keepttl=False, get=False, exat=None, pxat=None) |
如果key不存在就添加成功 | setnx(name, value) |
设置key的过期时间 | setex(name, time, value)以秒为单位,psetex(name, time_ms, value)以毫秒为单位 |
获取单个键值对 | get(name) |
设置多个键值对 | mset(*args, **kwargs) |
获取多个键值对 | mget(keys, *args) |
值不存在设新键值对 | getset(name, value) |
根据索引修改值 | setrange(name, offset, value) |
根据索引获取值 | getrange(key, start, end) |
根据建值追加值 | append(key, value) |
获取值长度 | strlen(name) |
String还有一个特点是:可以设置自增类型(不同类型设置不同类型的自增,注意区分)
incr(name, amount=1)
incrbyfloat(name, amount=1.0)
对于上面各个函数的用法如下:
单个键值对的用法
r.set("name", "码农研究僧")
r.get("name")
r.append("name", "大帅哥") # key后追加,不存在则不成功
"""
对于set的参数比较多,不同参数不同的延迟
"""
r.setex("name", 10086, "码农研究僧") # 10086秒后过期
# 类似
r.set("name", "码农研究僧", ex = 10086)
r.psetex("name", 10086, "码农研究僧") # 10086毫秒后过期
# 类似
r.set("name","码农研究僧",px = 10086)
r.setnx("name", "码农研究僧") # key不存在设置成功,也就是 新建 键值
# 类似
r.set("name", "码农研究僧",nx=True)
r.setxx("name", "码农研究僧") # key存在设置成功,也就是 修改 键值
# 类似
r.set("name", "码农研究僧",xx=True)
多个键值对的用法:
r.mset({'k1': 'v1', 'k2': 'v2'}) # 设置多个值,传入字典
r.mget("k1", "k2") # 返回一个列表,一次取出多个值
r.getset("name", "关注我") # 设置新值,并返回之前的值
# 类似
dict = {
'k1' : 'v1',
'k2' : 'v2'
}
r.mset(dict)
范围以及自增的用法:
r.setrange("name", 2, "开发") # 从第2个位置开始替换(0开始数),原来是码农研究僧,替换后是码农开发
r.getrange("name", 2, 3) # 取中间子串,为开发
r.strlen("name") # 长度,不存在为0
r.incr("name", amount=3) # 以3为自增,不存在则以3为初值,不指定amount则默认为1
r.incrbyfloat("name", amount=0.3) # 以0.3自增, 同理
r.decr("name", amount=3) # 递减同理
r.delete("name1") # 删除
描述 | 函数用法 |
---|---|
lpush(name,values) | 对应的name中往左添加list元素 |
rpush(name,values) | 对应的name中往右添加list元素 |
lpushx(name, value) | 往已有name的列表添加左元素,没有无法创建 |
rpushx(name, value) | 往已有name的列表添加左元素,没有无法创建 |
linsert(name, where, refvalue, value)) | 通过refvalue的where(可以before或者after)插入value |
r.lset(name, index, value) | 修改对应list列表中的某个索引值 |
r.lrem(name, num, value) | 删除list列表指定值 |
lpop(name) | 删除列表左边的第一个元素,返回删除的元素 |
rpop(name) | 删除列表右边的第一个元素,返回删除的元素 |
ltrim(name, start, end) | 删除索引之外的值 |
lindex(name, index) | 根据索引获取列表值 |
rpoplpush(list1,anotherlist1) | list1的列表中最右边的值插入anotherlist1列表的最左边 |
brpoplpush(list1,anotherlist1, timeout=0) | list1的列表中最左边的值插入anotherlist1列表的最右边 |
blpop(keys, timeout) | 一次移除多个列表 |
插入元素具体的使用用法:
r.lpush("list1", 1,2,3) # 从左插入,通过r.lrange('list1',0,2)得到321。list1不存在会创建
r.rpush("list2", 1,2,3) # 从右插入,通过r.lrange('list2',0,2)得到123
r.lpushx("list1", 4,5) # 从左插入,通过r.lrange('list1',0,5)得到45321
r.rpushx("list1", 4,5) # 从右插入,通过r.lrange('list1',0,6)得到453216
其他的增删改查的一些指标:(查看最后的值,通过r.lrange('list4',0,-1)
).
python的输出格式有多种:可通过如下format格式print("list4:{}".format(r.lrange('list4',0,-1)))
r.lrange("list1",0,-1) # 默认是输出全部值,返回所有列表
r.llen("list1") # 返回元素个数
r.lindex("list1", 1) # 通过下标1的取值
r.linsert("list1", "before", 5,3) # 5之前插入3,本身值为453216,最后为4353216
r.lset("list1", 2, 6) # 修改第2个元素为6,最后值为456216
r.rpush("list4", 2,2,1,2,3,4,5,6,1,1) # 从右插入,通过r.lrange('list4',0,-1)得到1212345611
r.lrem("list4", 1, 2) # 删除左边的第一个2
r.lrem("list4", -1, 1) # 删除右边的第一个1,负数为从后往前
r.lrem("list4", 0, 1) # 删除所有的1
r.lpop("list4") # 删除左边第一个值并返回删除值
r.rpop("list4") # 删除右边第一个值并返回删除值
r.ltrim("list4", 2, 3) # 除了下标2到3的元素,其他都被删除
描述 | 函数用法 |
---|---|
hset(name, key, value) | 设置键值对。有即修改无即创建 |
hget(name, key) | 取出单个key的值 |
hmget(name, key,…) | 取出多个key的值 |
hgetall(name) | 取出对应的所有键值对 |
hkeys(name) | 取出所有的key |
hvals(name) | 取出所有的value |
hlen(name) | 取出键值对个数 |
hexists(name, key) | 查看是否存在这个key |
自增以及分片的函数
主要为了防止多次取值,撑爆内存
具体的思想通过
在应用场景中比较常用,所以单独放在一个表格中:
描述 | 函数用法 |
---|---|
hincrby(name, key, amount=?) | 对key自增正或者负 |
hincrbyfloat(name, key, amount=?.0) | 对key自增正浮点数或者负浮点数 |
hscan(name, cursor=0, match=None, count=None) | 指定游标获取数据 |
hscan_iter(name, match=None, count=None) | 同上,只不过将其封装在迭代器 |
具体操作如下:
r.hset("names", "manong", "yanjiuseng") # 设置键值对
r.hmset("names", {"manong": "yanjiuseng", ....}) # 设置多个键值对,redis4.0版本前
r.hset("names", mapping={"manong": "yanjiuseng", ...}) # 设置多个键值对,redis4.0版本后
r.hget("names", "manong") # 取出key中对应的value值,返回其value值
r.hmget("names", ["manong", "age"]) # 取出多个key中对应的value值,返回其value值
r.hgetall("names") # 取出多有的键值对(字典)
r.hkeys("names") # 取出所有key(列表)
r.hvals("names") # 取出所有value(列表)
hlen("names") # 获取键值对个数
r.hexists("names", "ma") # 查看是否存在这个key
r.hincrby("names", "age", amount=1)
# 自增1,age本身这个就没设置,则以amount为初始,也可为负数
分片读取的具体操作:
cursor1, data1 = r.hscan('names', cursor=0, match=None, count=None)
cursor2, data2 = r.hscan('names', cursor=cursor1, match=None, count=None)
r.hscan_iter("names", match=None, count=None) # 取出所有key,注意这里要用遍历,将其值进行遍历出来
# 具体如下
for item in r.hscan_iter('xx'):
print item
set元素本身是无序不可重复
描述 | 函数用法 |
---|---|
sadd(name,values) | 集合中添加一个或多个元素 |
sismember(name, value) | 判断集合name中是否有对应value元素,返回false或者true |
smove(src, dst, value) | 将src集合中的value元素移动到dst集合中 |
sdiff(keys, *args) | 返回只存在第一个集合names中,之后的names集合都排除掉(差集) |
sdiffstore(dest, keys, *args) | 只存在第二个集合的names,之后的names集合都排除掉,放在第一个dest集合中 |
sinter(keys, *args) | 多个集合names取交集 |
sinterstore(dest, keys, *args) | 多个names取交集,存放在第一个dest集合中 |
sunion(keys, *args) | 多个集合names取并集 |
sunionstore(dest,keys, *args) | 多个集合names取并集,存放在第一个dest集合中 |
spop(name) | 随机删除元素,并且返回输出该元素 |
srem(name, values) | 删除集合中指定的value值,并返回已经删除的元素个数 |
新增元素以及查询等操作:
r.sadd("names", "ma", "nong", "yan", "jiu", "seng") # 返回集合长度个数5
r.sismember("names", "ma") # 查询 ma 元素是否存在,返回false或者true操作
r.scard("names") # 获取集合元素个数
# 补充测试输出的时候,可以通过如下:
print('集合元素个数:{}'.format(r.scard("names")))
r.smembers("names") # 返回所有集合元素
r.sscan('names') #返回集合的所有元素(以元祖形式展示)
r.scan_iter("names") # 返回集合所有元素(需要通过遍历的形式输出)
# 例如
for i in r.sscan_iter("names"):
print(i)
差集的操作:
r.sdiff("names1", "names2") # 返回存在names1不存在names2的集合元素
r.sdiffstore("names3", "names1", "names2") # 存在names1不存在names2的集合元素,存放在names3中,并且输出这个集合
交集的操作:
r.sinter("names1", "names2") # 返回names1和names2的交集元素
r.sinterstore("names3", "names", "names2") # 把names和names2的交集存到names3,返回names3的元素
并集的操作:
r.sunion("names1", "names2") # 返回names1和names2的并集元素
r.sunionstore("names3", "names1", "names2") # 把names和names2的并集存到names3,返回names3的元素
差集的操作:
r.spop("names") # 随机删除一个元素,并且将这个元素返回输出
r.srem("names", "ma") # 删除指定元素ma,返回已经删除的个数
这个zset与set的区别在于
zset为有序集合,会为元素进行排序
描述 | 函数用法 |
---|---|
zadd(name, {‘k1’:v1,‘k2’:v2}) | 有序集合中添加元素 |
zcard(name) | 获取有序集合元素个数 |
r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float) | 获取有序集合的元素。desc 为排序规则, 默认是value从小到大排序。withscores是否获取value,默认不获取value只有key。score_cast_func对value进行转换的函数 |
zrevrange(name, start, end, withscores=False, score_cast_func=float) | 同上,只不过集合默认为从大到小排序 |
zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float) | 对应value值获取其对应key以及value元素,默认value从小到大 |
zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float) | 同上,只不过value默认是从大到小 |
zscan(name, cursor=0, match=None, count=None, score_cast_func=float) | 获取所有的value,默认value从小到大 |
zcount(name, min, max) | 统计value在min以及max的元素个数 |
zincrby(name, amount, value) | 对应name的集合中的value分数,每次都自增amount |
zrank(name, value) | 获取集合name中的value排在第几,导出从小到大的正序的索引号 |
zrevrank(name, value) | 同上,只不过是从大到小的正序索引号 |
zscore(name, key) | 获取集合name中key对应的value值 |
zrem(name, key) | 删除集合name中的单个key值 |
zremrangebyrank(name, min, max) | 删除对应的索引元素(将其value进行从小到大进行排序) |
zremrangebyscore(name, min, max) | 删除value范围在min以及max之间的(将其value进行从小到大进行排序) |
获取元素的key以及对应value,具体操作:
r.zadd("names", {"ma": 1, "nong": 2, "yan": 3}) # 新增元素,而且设置对应的key以及value
r.zcard("names") # 返回有序集合个数长度
r.zrange("names", 0, -1) # 取出集合names中所有元素的key
r.zrange("names", 0, -1, withscores=True) # 取出集合names中所有元素 正序 排序,有key以及value
r.zrevrange("names", 0, -1, withscores=True) # 同上,倒序操作
r.zrangebyscore("names", 1, 3, withscores=True) # 取出集合中的value范围在1-3之间的,value按照从小到大输出对应的key以及value
r.zrevrangebyscore("names", 1, 3, withscores=True) # 同上,从大到小的输出
r.zscan("names") # 取出所有有序集合的元素
r.zscan_iter("names") # 获取所有元素,这是一个迭代器
#具体操作如下:
for i in r.zscan_iter("names"): # 遍历迭代器
print(i)
计数、自增、获取索引以及删除等具体操作:
r.zcount("names", 1, 3) # 统计value在1-3之间的元素个数,并且返回
r.zincrby("names", 2, "ma") # 将ma的value自增2
r.zscore("names", "ma") # 返回key对应的value
r.zrank("names", "ma") # 返回元素ma的下标(从小到大排序)
r.zrerank("names", "ma") # 返回元素ma的下标(从大到小排序)
r.zrem("names", "ma") # 删除单个key
r.zremrangebyrank("names", 0, 2) # 删除下标在0到2间的元素
r.zremrangebyscore("names", 1, 3) # 删除value在1-3之间的元素
结合python web开发
通过表单获取redis的数据
通过普通连接或者连接池连接
连接成功之后获取想要的数据传回到表单即可
调用一般的redis函数,或者自已封装一个连接函数
def get_redis(config):
sentinels = config.get("sentinels", "")
cluster_tag = config.get("cluster_tag", "")
if all([sentinels, cluster_tag]):
sentinel = Sentinel(sentinels, socket_timeout=5)
REDIS = sentinel.master_for(cluster_tag, socket_timeout=5)
else:
REDIS = StrictRedis(host=config.get("host", "127.0.0.1"),
port=config.get("port", 6379))
return REDIS
一般企业都会有很清晰的流水线
如果划分了dev以及生产环境,不同的redis集群配置放不同配置
这部分是setting的公共配置
REDIS_CACHES = {
'manongyanjiuseng': {
'type': 'sentinel',
'cluster_tag': 'manongyanjiuseng_test',
'host': [
("ip", 端口号),
("https://blog.csdn.net/weixin_47872288", 端口号),
("https://blog.csdn.net/weixin_47872288", 端口号),
],
'socket_timeout': 10,
'master': 1,
'db': 3
},
# 同理如上创建
}
公共类的函数都放在common.py中
import redis
from redis.sentinel import Sentinel
from redis import StrictRedis
# 初始化一个线程池
CONNECTION_POOL = {}
# 定义连接的参数
def get_redis_connection(server_name='default'):
# 函数内部可改变函数外部的变量,所以定义global
global CONNECTION_POOL
if not CONNECTION_POOL:
CONNECTION_POOL = _setup_redis()
pool = CONNECTION_POOL[server_name]
if settings.REDIS_CACHES[server_name].get("type") == "sentinel":
return pool
return redis.Redis(connection_pool=pool)
def _setup_redis():
for name, config in settings.REDIS_CACHES.items():
if config.get("type") == "sentinel":
sentinel = Sentinel(config['host'], socket_timeout=config['socket_timeout'])
if config.get('master'):
pool = sentinel.master_for(
config["cluster_tag"],
redis_class=redis.Redis,
socket_timeout=config['socket_timeout']
)
else:
pool = sentinel.slave_for(
config["cluster_tag"],
redis_class=redis.Redis,
socket_timeout=config['socket_timeout']
)
else:
pool = redis.ConnectionPool(
host=config['host'],
port=config['port'],
db=config['db'],
socket_timeout=1
)
CONNECTION_POOL[name] = pool
return CONNECTION_POOL
在调用连接的时候通过如下:
# manong这个值是通过form表单传入进去的
redis = get_redis_connection(manong)