栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python操作Redis从入门到精通附代码(全)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python操作Redis从入门到精通附代码(全)

目录
  • 前言
  • 1. 连接Redis
  • 2. 基本类型
    • 2.1 String
    • 2.2 List
    • 2.3 Hash
    • 2.4 Set
    • 2.5 Zset
  • 3. 实战
    • 3.1 普通连接
    • 3.2 连接池连接

前言

对于Redis的相应原理以及知识点对应的java版本,可看我之前的文章:(其知识点都是互通的)
Redis框架从入门到学精(全)

对于以上的前置知识如果了解了更好,如果不了解,就当是一种数据库,上手也很快。
本身Redis就是一种可持久的Key-Value的数据库,有丰富的数据结构等

通过pip install redis进行安装导入redis的模块包即可
如果在安装以及使用的过程中遇到这些bug
可看我之前的文章:

  1. Redis (error) NOAUTH Authentication required.解决方法
  2. Redis Could not connect to Redis at 127.0.0.1:6379: Connection refused解决方法
  3. linux中设置redis的密码
  4. Redis出现 Creating Server TCP listening socket *:6379: bind: No error 的解决方法(全)
1. 连接Redis

本身就是一种数据库,操作数据库第一就是连接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)
2. 基本类型

在基本类型中介绍其方法的使用
正常连接之后 大部分都可通过如下查看其共性的东西:
通过set设置键值对:redis.set('manong',18)
获取键值:redis.get('manong')
判断键值是否存在:redis.exists('manong')
查看键值的类型:redis.type('manong')
获取当前数据库中键值对数目:redis.dbsize()
以及其他的函数,可参照官网进行学习

基本的使用类型以及方法会用即可

2.1 String

其实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")  # 删除
2.2 List
描述函数用法
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的元素,其他都被删除
2.3 Hash
描述函数用法
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

自增以及分片的函数
主要为了防止多次取值,撑爆内存
具体的思想通过

  1. 通过cursor的标志位置获取数据
  2. match参数过滤,如果指定None则为所有key,如果指定key则过滤key出来
  3. count每次最少取key的个数,为None则为默认分片的个数

在应用场景中比较常用,所以单独放在一个表格中:

描述函数用法
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
2.4 Set

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,返回已经删除的个数
2.5 Zset

这个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之间的元素
3. 实战

结合python web开发
通过表单获取redis的数据
通过普通连接或者连接池连接
连接成功之后获取想要的数据传回到表单即可

3.1 普通连接

调用一般的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

3.2 连接池连接

一般企业都会有很清晰的流水线
如果划分了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)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994313.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号