设为首页 收藏本站
查看: 969|回复: 0

[经验分享] Python自动化开发学习11-Redis

[复制链接]
累计签到:2 天
连续签到:1 天
发表于 2018-8-5 10:07:45 | 显示全部楼层 |阅读模式
Redis-缓存系统
  缓存系统也可以叫缓存数据库,现在主流的系统有 Redis 和 Memcached :
  MongoDB,比较早的缓存系统,直接持久化到硬盘
  Redis,现在正火的。半持久化数据,数据默认存在内存中,可以持久化到硬盘里持久保存。效率高,在单线程下运行,通过epoll实现的高并发
  Memcached,轻量级的缓存系统,不能持久化只能存在内存中。相对应该比较简单,可以自学?

安装
  通过yum安装就好了,在epel源里:
  

$ yum install redis  

  开放防火墙:
  

$ firewall-cmd --permanent --add-port=6379/tcp  
$ firewall-cmd --reload
  

  开启服务:
  

$ redis-server  

  可以在命令后面加上 & ,这样启动后就是运行在后台。如果再后台运行想停止服务:
  

$ redis-cli shutdown  

  另外,redis默认是以保护模式启动的,只能本机连。你的redis可能不是运行在本机的,比如在虚拟机上,那么本机以外可能连不上,或者只能连不能改。就不要那么麻烦再去整配置文件了,这里以学习测试为主,推荐这么启动:
  

$ redis-server --protected-mode no  

  你也可以根据需要加上 & 启动后再后台运行。配置文件什么的用的时候再去研究吧,这里我们搭建学习环境。
  可以先进入redis的命令行界面里简单操作一下,进入命令行界面:
  

$ redis-cli  

  简单的存一个值:
  

> set age 23  

  age是key,23是value,取出age的值:
  

> get age  

  查看已经存了哪些key:
  

> keys *  

  存值,有存活时间:
  

> set city ShangHai ex 2  

  上面存的值只能存活2秒,超过时间再去get,返回的就是(nil)
  帮助命令很有用,有不清楚的,可以看下命令的语法和说明
  

> help [ 命令 ]  

redis 模块
  使用python操作redis,需要安装第三方模块,模块名也叫redis。

Redis API 使用
  redis-py 的API的使用可以分类为:


  • 连接方式

    • 连接
    • 连接池

  • 操作

    • String 操作
    • Hash 操作
    • List 操作
    • Set 操作
    • Sort Set 操作

  • 管道
  • 发布订阅
  参考资料:
  https://github.com/andymccurdy/redis-py/
  Redis 命令参考(中文翻译版):http://doc.redisfans.com/

连接方式
  先来连接redis,然后把上面命令行界面里的操作在python上再做一遍:
  

import redis, time  
r = redis.Redis('192.168.3.108', 6379)  # 使用连接池连接,把这句注释掉
  
# pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
# r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  
r.set('age', 23)
  
print(r.get('age'))
  
r.set('city', 'ShangHai', 2)
  
print(r.get('city'))
  
time.sleep(1)
  
print(r.keys('*'))
  
print(r.get('city'))
  
time.sleep(1)
  
print(r.get('city'))
  

  上面注释的部分给了另外一种通过连接池连接的方式,使用的时候,推荐使用连接池连接:
  redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。

String 操作
  redis中的String在内存中是按照一个key对应一个value来存储。
  set(name, value, ex=None, px=None, nx=False, xx=False) :设置值,默认如果key不存在则创建,key存在则修改
  可选参数:


  • ex :过期时间(秒)
  • px :过期时间(毫秒)
  • nx :若设为True,只有name不存在时,set操作才执行
  • xx :若设为True,只有name存在时,set操作才执行
  setnx(name, value) :效果同上面的 ns=True
  setex(name, value, time) :效果同上面的 ex=time
  psetex(name, time_ms, value) :效果同上面的 px=time_ms
  get(name) :获取值
  mset(*args, **kwargs) :批量设置
  mget(keys, *args) :批量获取
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.mset(k1='v1', k2='v2')  # 可以用关键参数的方法
  
r.mset({'k3': 'v3', 'k4': 'v4'})  # 也可以用字典的方式
  
print(r.mget('k1', 'k2', 'k3'))  # 可以一个一个把key传入
  
print(r.mget(['k2', 'k3', 'k4']))  # 也可以直接传个列表(元组也行啊)
  

  getset(name, value) 获取name的当前值,然后给name赋一个新的值
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
for i in range(10):
  n = r.getset('count', i)  # 取出当前值赋值给n,然后再存入一个新的值
  print(n)
  

  getrange(key, start, end) :获取子序列,相当于列表切片(字符串也可以当列表操作)
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.set('hello', 'Hello World!')
  
print(r.getrange('hello', 3, 4))
  
r.set('hello_ch', '你好')
  
print(r.getrange('hello_ch', 0, 2).decode('utf-8'))  # 一个中文字符在utf-8中占3个字符
  

  setrange(name, offset, value) :修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.set('hello', 'Hello World!')
  
r.setrange('hello', 1, 'ELL')  # 从位置 1 开始替换
  
print(r.get('hello'))
  

  setbit(name, offset, value) :修改字符串内容,这里按二进制的bit位进行操作。上面那个是按字节操作
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.set('hello', 'Hello World!')
  
r.setbit('hello', 2, 1)  # 一个ASCII字符是8位,H的编码是0100 1000,变成0110 1000后就是'h'
  
print(r.get('hello'))
  

  getbit(name, offset) :获取name对应的值的二进制表示中的那一位的值,不是0就是1
  bitcount(key, start=None, end=None) :获取name对应的值的二进制表中 1 的个数,加上 start 和 end 参数限制统计的范围

按位操作的应用场景
  用最省空间的方式,存储在线用户数及分别是哪些用户在线。
  用户状态只有2种,0离线,1在线。每个用户的状态只占1个位,每个用户都有一个用户id,用户id就是这个用户状态存储在变量中的 offset 的位置,具体看代码示例:
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  


  
r.setbit('user_state', 10, 1)  #>
  
r.setbit('user_state', 101, 1)  #>
  
r.setbit('user_state', 311, 1)  #>  
print(r.bitcount('user_state'))  # 现在有多少用户在线,只要统计都有说少个1

  
print(r.getbit('user_state', 11))  #>  
# 如果有另外一份用户资料的数据,存储着用户的详细信息,包括id,那么你就可以通过这个id获取到该用户的详细数据,比如用户名,等等

  
print(r.getbit('user_state', 101))  #>  

  bitop(operation, dest, *keys) :获取keys的值,按照operation的方法做位运算,结果赋值给dest。用不到
  strlen(name) :返回name对应值的字节长度(一个汉字3个字节)
  incr(name, amount=1) :自增 name 对应的值,当 name 不存在时,则创建 name=amount
  decr(name, amount=1) :自减 name 对应的值,当 name 不存在时,则创建 name=amount
  incrbyfloat(name, amount=1.0) :和上面差不多,支持浮点型数值
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
for i in range(10):
  print(r.incrbyfloat('money', 1.23))
  

  append(key, value) :在 key 的 value 值后面追加内容
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.set('name', 'Barry')
  
print(r.get('name'))
  
r.append('name', ' Allen')
  
print(r.get('name'))
  

Hash 操作
  hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据
  hset(name, key, value) :在name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
  hmset(name, mapping) :在name对应的hash中批量设置键值对
  hget(name, key) :在name对应的hash中根据key获取value
  hmget(name, keys, *args) :在name对应的hash中获取多个key的值
  hgetall(name) :获取name对应hash的所有键值,key 和 value都获取,但是无法区分
  hlen(name) :获取name对应的hash中键值对的个数
  hkeys(name) :获取name对应的hash中所有的key的值
  hvals(name) :获取name对应的hash中所有的value的值
  hexists(name, key) :检查name对应的hash是否存在当前传入的key
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.hset('Barry', 'family_name', 'Allen')  # 一次设置一对 key 和 value
  
r.hset('Barry', 'sex', 'Male')
  
r.hset('Barry', 'color', 'red')
  
r.hmset('Oliver', {'family_name': 'Queen', 'sex': 'Male', 'color': 'green'})  # 一次设置一个字典
  

  
print(r.hget('Barry', 'color'))  # 取一个值
  
print(r.hmget('Barry', ['sex', 'color']))  # 取多个值,通过字典的方法,对应keys
  
print(r.hmget('Barry', 'sex', 'color'))  # 取多个值,通过关键参数的方法,对应*args
  
print(r.hlen('Barry'))  # 一共有多少对 key 和 value
  
print(r.hgetall('Barry'))  # 取所有的 key 和 value
  
print(r.hkeys('Barry'))  # 取所有的 key
  
print(r.hvals('Barry'))  # 取所有的 value
  
print(r.hexists('Barry', 'age'), r.hexists('Barry', 'sex'))
  

  hdel(name,*keys) :将name对应的hash中指定key的键值对删除
  hincrby(name, key, amount=1) :自增name对应的hash中的指定key的值,不存在则创建key=amount
  hincrbyfloat(name, key, amount=1.0) :自增name对应的hash中的指定key的值,不存在则创建key=amount

scan方法-用于获取大量的数据
  hscan(name, cursor=0, match=None, count=None) :增量式迭代获取,对于获取数据量很大的数据时非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而防止内存被撑爆。参数:


  • name :redis的name
  • cursor :游标(基于游标分批取获取数据)
  • match :匹配指定key,默认None表示所有的key。可以用通配符,? * 等,具体参考其他常用操作中的 keys 命令的参数
  • count :每次分片最少获取个数,默认None表示采用Redis的默认分片个数
  hscan_iter(name, match=None, count=None) :利用yield封装hscan创建生成器,实现分批去redis中获取数据

List 操作
  redis中的List在在内存中是按照一个name对应一个List来存储。
  lpush(name,values) :在name对应的list中添加元素,每个新的元素都添加到列表的最左边
  rpush(name,values) :同上,添加到右边
  llen(name) :name对应的list元素的个数
  lrange(name, start, end) :在name对应的列表分片获取数据,要获取列表全部,就 0, -1
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 清空这个name
  
r.lpush('names', 'Clark', 'Lois', 'Kara')  # 依次插入每一个值,每次都是插入到列表最左边
  
print(r.lrange('names', 0, -1))  # 查看输出时的排序,和上面是反的
  
print(r.llen('names'))  # 列表的长度
  
r.rpush('names', 'Barry')  # 插入到最右边
  
r.lpush('names', 'Oliver')  # 插入到最左边,只有names已经存在时才会添加进来
  
print(r.lrange('names', 0, -1))
  

  lpushx(name,value) :在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
  rpushx(name,value) :同上,添加到右边
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 清空这个name
  
r.rpushx('names', 'Barry')
  
r.lpushx('names', 'Oliver')
  
print(r.lrange('names', 0, -1))  # names不存在,无法添加
  
r.lpush('names', 'Clark')  # 现在已经创建了这个列表了
  
r.rpushx('names', 'Barry')
  
r.lpushx('names', 'Oliver')
  
print(r.lrange('names', 0, -1))  # 只有names已经存在的时候才能向列表中添加元素
  

  linsert(name, where, refvalue, value)) :在name对应的列表的某一个值前(‘before’)或后(‘after’)插入一个新值
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 清空这个name
  
r.rpush('names', 'Barry', 'Oliver', 'Kara')
  
print(r.lrange('names', 0, -1))
  
r.linsert('names', 'before', 'Oliver', 'Laurel')  # 在标杆前面插入
  
r.linsert('names', 'after', 'Kara', 'Sara')  # 在标杆后面插入
  
print(r.lrange('names', 0, -1))
  

  r.lset(name, index, value) :对name对应的list中的某一个索引位置重新赋值
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 清空这个name
  
r.rpush('names', 'Barry', 'Oliver', 'Kara')
  
r.lset('names', 1, 'Oliver Queen')  # 根据索引值修改元素
  
print(r.lrange('names', 0, -1))
  

  r.lrem(name, value, num) :在name对应的list中删除指定的值。num为0删除所有;num为正数,从前往后删除num个;num为负数,从后向前删除num个。
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 清空这个name
  
r.rpush('names', 'Barry', 'Oliver', 'Kara', 'Clark')
  
r.rpush('names', 'Barry', 'Oliver', 'Kara', 'Clark')
  
r.rpush('names', 'Barry', 'Oliver', 'Kara', 'Clark')
  
print(r.lrange('names', 0, -1))  # 现在每个值都有3个
  
r.lrem('names', 'Barry')  # num默认是0,删除所有的Barry
  
print(r.lrange('names', 0, -1))
  
r.lrem('names', 'Oliver', 1)  # 删除最前面的1个Oliver
  
r.lrem('names', 'Kara', -2)  # 删除最后面的2个Kara
  
print(r.lrange('names', 0, -1))
  

  lpop(name) :在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
  rpop(name) :同上,从右侧获取并移除
  lindex(name, index) :使用下标获取值
  ltrim(name, start, end) :移除 start 和 end索引位置以外的值
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  
r.delete('names')  # 清空这个name
  
r.rpush('names', 'Barry', 'Oliver', 'Kara', 'Clark')
  

  
print(r.lindex('names', 1))  # 看看下标1是哪个元素
  
print(r.lrange('names', 0, -1))
  
r.ltrim('names', 1, 2)  # 移除1-2以外的元素,保留1-2的这些元素。如果start和end一样,就只保留那一个元素
  
print(r.lrange('names', 0, -1))
  
print(r.lpop('names'))  # 从左边弹出一个值
  
print(r.rpop('names'))  # 从右边弹出一个值
  
print(r.lrange('names', 0, -1))  # 列表应该空了
  

  rpoplpush(src, dst) :从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
  

import redis  
pool = redis.ConnectionPool(host='192.168.246.11', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  
r.delete('Oliver', 'Rip')
  

  
r.rpush('Oliver', 'Thea', 'Laurel', 'Sara', 'Ray')
  
r.rpush('Rip', 'Nate', 'Amaya')
  

  
res = r.rpoplpush('Oliver', 'Rip')  # 转移一个元素
  
print(res)
  
print(r.rpoplpush('Oliver', 'Rip'))  # 再转移一个元素
  
print(r.lrange('Oliver', 0, -1))
  
print(r.lrange('Rip', 0, -1))
  

阻塞的pop方法
  下面的2个pop方法和前面不带b开头的方法基本上是一样的,但是多了一个timeout参数。在timeout的时间内如果列表中没有值,则阻塞,一旦有值进来,就会取出来。非常像队列的操作。timeout如果是0,则一直阻塞,直到取到值。如果timeout时间到还没取到值,会返回None。
  blpop(keys, timeout) :将多个列表排列,按照从左到右去pop对应列表的元素。这里keys可以是多个name
  brpop(keys, timeout) :同上,每个列表中取元素的时候是从右开始
  brpoplpush(src, dst, timeout=0) :
  blpop 和 brpop 和前面略有不同,可以从多个列表中取值,具体效果如下:
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('Rip', 'Barry', 'Oliver')  # 先清空数据
  
r.rpush('Rip', 'Nate')  # 第1个列表有1个元素
  
r.rpush('Barry', 'Cisco', 'Caitlin')  # 第2个列表有2个元素
  
r.rpush('Oliver', 'Thea', 'Laurel', 'Roy')  # 第3个列表有3个元素
  

  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 先取第1个列表
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 第1个空了,会取第2个列表
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 前2个列表都空了,会取取第三个
  
r.rpush('Rip', 'Leonard')  # 往第一个列表中追加一个新元素
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 还是从第一个列表开始取
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 所有列表都空了的话,会阻塞
  
print(r.blpop(['Rip', 'Barry', 'Oliver'], 1))  # 如果timeout不为0,时间到了之后会返回None
  

Set 集合操作
  Set集合就是不允许重复的列表,并且集合是无序的。后面有有序集合
  sadd(name,values) :name对应的集合中添加元素
  scard(name) :获取name对应的集合中元素个数
  smembers(name) :获取name对应的集合的所有成员
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 先清空数据
  
r.sadd('names', 'Clerk', 'Lois', 'Clerk')  # 一次可以添加多个元素,这里故意加了2个一样的
  
print(r.scard('names'))  # 集合的特性就是会去重,这里只有2个元素
  
print(r.smembers('names'))  # 看下所有的元素
  

  sdiff(keys, *args) :差集,返回一个集合
  sdiffstore(dest, keys, *args) :同上,返回值是新集合的元素个数,新集合存储到dest中
  sinter(keys, *args) :交集,返回一个集合
  sinterstore(dest, keys, *args) :同上,返回值是新集合的元素个数,新集合存储到dest中
  sunion(keys, *args) :并集,返回一个集合
  sunionstore(dest,keys, *args) :同上,返回值是新集合的元素个数,新集合存储到dest中
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('Rip', 'Oliver')  # 先清空数据
  
r.sadd('Rip', 'Nate', 'Ray', 'Sara')
  
r.sadd('Oliver', 'Thea', 'Laurel', 'Sara', 'Ray')
  

  
print(r.sdiff('Rip', 'Oliver'))
  
# 返回值是符合条件的元素数量,比上面多一个参数,用来存放结果作为新的集合
  
print(r.sdiffstore('Sara', 'Rip', 'Oliver'))
  
print(r.smembers('Sara'))
  

  sismember(name, value) :values 是否是 name 集合的成员
  smove(src, dst, value) :将某个成员从一个集合中移动到另外一个集合
  spop(name) :从集合的右侧(尾部)移除一个成员,并将其返回
  srandmember(name, numbers) :从name对应的集合中随机获取 numbers 个元素,默认就取1个,可以取多个。
  srem(name, values) :在name对应的集合中删除某些值
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('Oliver')  # 先清空数据
  
r.sadd('Oliver', 'Thea', 'Laurel', 'Sara', 'Ray')
  
r.srem('Oliver', 'Ray', 'Sara', 'Roy')  # 有的元素全部从集合里删除,没有的value不影响
  
print(r.smembers('Oliver'))
  

  同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法
  sscan(name, cursor=0, match=None, count=None)
  sscan_iter(name, match=None, count=None)

有序集合
  有序集合,在集合的基础上,为每个元素排序,元素的排序需要根据另外一个值来进行比较。所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。
  zadd(name, *args, **kwargs) :在name对应的有序集合中添加元素,每个成员都要有一个分数,2种可是可选,看例子
  zcard(name) :获取name对应的有序集合元素的数量
  zcount(name, min, max) :也是统计集合的元素数量,但是是满足分数在 min 和 max 之间的元素的数量
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 先清空数据
  
r.zadd('names', 'Clerk', 1, 'Barry', 6, 'Oliver', 3)  # *args的方式添加成员
  
print(r.zcard('names'))  # 查看成员数量
  
print(r.zrange('names', 0, -1))  # 按分数从小到大排列
  
print(r.zcount('names', 2, 5))  # 分值在2-5之间的只有1个成员
  
r.zadd('names', Barry=2)  # **kwargs的方式添加成员,如果添加已有的成员则是更新分数
  
print(r.zrange('names', 0, -1))  # 分数有变化了,排序也变了
  
print(r.zcount('names', 2, 5))  # 分值在2-5之间的成员现在有2个了
  

  zincrby(name, value, amount) :自增name对应的有序集合的 value 对应的分数,默认自增1
  r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float) :按照索引范围获取有序集合的元素
  参数:


  • name :
  • start :有序集合索引起始位置(非分数)
  • end :有序集合索引结束位置(非分数)
  • desc :排序规则,默认按照分数从小到大排序
  • withscores :是否获取元素的分数,默认只获取元素的值
  • score_cast_func :对分数进行数据转换的函数
  r.zrevrange( name, start, end, withscores=False, score_cast_func=float) :另一种从大到小排列的方法
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 先清空数据
  
r.zadd('names', Clerk=1, Barry=3, Oliver=2)
  
r.zincrby('names', 'Barry')  # 默认自增1
  
r.zincrby('names', 'Oliver', 3)  # 指定多加点
  
print(r.zrange('names', 0, -1))  # 默认从小到大排列
  
print(r.zrange('names', 0, -1, desc=True))  # 从大到小排列
  
print(r.zrevrange('names', 0, -1))  # 另一种方法从大到小排列
  
print(r.zrange('names', 0, -1, withscores=True))  # 显示分数
  
print(r.zrange('names', 0, -1, withscores=True, score_cast_func=int))  # 整形的分数
  

  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) :同上,从大到小
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 先清空数据
  
r.zadd('names', Clerk=1, Barry=2, Oliver=3)
  
print(r.zrangebyscore('names', 2, 3))
  
print(r.zrevrangebyscore('names', 3, 2))  # 注意这里分数也是先max,再min
  

  r.zrangebylex(name, min, max, start=None,num=None) :跳过,没讲,不好理解还用不上
  r.zrevrangebylex(name, max, min, start=None,num=None) :同上,从打到小排列
  r.zremrangebylex(name, min, max) :跳过
  zrank(name, value) :获取某个值在 name 对应的有序集合中的排行(从 0 开始)。可以做班级成绩的排名
  zrem(name, values) :删除name对应的有序集合中值是values的成员,删除单个或多个成员
  zremrangebyrank(name, min, max) :根据排行范围删除
  zremrangebyscore(name, min, max) :根据分数范围删除
  zscore(name, value) :获取name对应有序集合中 value 对应的分数
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('names')  # 先清空数据
  
r.zadd('names', Kara=95, Harley=55, Diana=100, Barbara=94, Janet=88, Wally=89)  # 这是成员和成绩
  
print(r.zrank('names', 'Diana'))  # 从小到大,从0开始的rank值
  
print(r.zcard('names')-r.zrank('names', 'Diana'))  # 这个就是成绩排名了
  
print(r.zscore('names', 'Diana'))  # 显示分数
  
r.zrem('names', 'Wally')  # 删除1个元素
  
print(r.zrange('names', 0, -1))
  
r.zremrangebyscore('names', 0, 59)  # 把成绩不及格的删除
  
print(r.zrange('names', 0, -1))
  
r.zremrangebyrank('names', 0, 0)  # 再把成绩最后一名删除
  
print(r.zrange('names', 0, -1))
  

  zinterstore(dest, keys, aggregate=None) :获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
  zunionstore(dest, keys, aggregate=None) :获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
  aggregate的值为:  SUM  MIN  MAX
  

import redis  
pool = redis.ConnectionPool(host='192.168.3.108', port=6379)  # 建立连接池
  
r = redis.Redis(connection_pool=pool)  # 使用连接池连接
  

  
r.delete('physics', 'chemistry')  # 先清空数据
  
r.zadd('physics', 'XiaoMing', 90)  # 小明物理考了90分
  
r.zadd('chemistry', 'XiaoMing', 66)  # 小明化学考了66分
  

  
r.zinterstore('score', ['physics', 'chemistry'], 'MAX')  # 分数只取2门里高的那门,MAX
  
print(r.zrange('score', 0, -1, withscores=True))  # 最后综合的分数是这个
  

  同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法
  zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
  zscan_iter(name, match=None, count=None,score_cast_func=float)

其他常用操作
  delete(*names) :根据删除redis中的任意数据类型
  flushdb() :删除当前db的所有数据
  flushall() :删除所有db的所有数据
  exists(name) :检测redis的name是否存在
  keys(pattern='*') :根据模型获取redis的name,pattem参数可以使用通配符匹配,参考如下:


  • KEYS * 匹配数据库中所有 key
  • KEYS h?llo 匹配 hello , hallo 和 hxllo 等
  • KEYS h*llo 匹配 hllo 和 heeeeello 等
  • KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
  expire(name ,time) :为name设置超时时间。这个方法可以不必在赋值的时候就设置时间了,而且还能用于更新时间
  rename(src, dst) :为name重命名
  move(name, db)) :将name移动到另外一个db中

关于db
  db就是数据库,当 redis 服务器初始化时,会预先分配 16 (0-15)个数据库(该数量可以通过配置文件配置)。
  之前的操作都是在默认的db=0下操作的。
  cli命令行界面下,使用select命令切换库。python中可以在建立连接的时候声明连接哪个库。
  删除数据和db的操作:
  

import redis  
pool1 = redis.ConnectionPool(host='192.168.246.11', port=6379, db=1)  # 建立连接池,连接db1
  
r1 = redis.Redis(connection_pool=pool1)  # 使用连接池连接
  
r2 = redis.Redis('192.168.246.11', 6379, db=2)  # 连接db2
  

  
r1.mset(k1='v1', k2='v2', k3='v3')
  
r2.mset(k1='v1', k2='v2', k3='v3')
  
print(r1.keys())
  
r1.delete('k1')  # 删除db1里的k1
  
print(r1.keys())
  
r1.flushdb()  # 删除db1里的所有
  
print(r1.keys())
  
print(r2.keys())
  
print(r1.flushall())  # 通过db1删除所有的db
  
print(r2.keys())
  

  移动、重命名:
  

import redis  
pool1 = redis.ConnectionPool(host='192.168.246.11', port=6379, db=1)  # 建立连接池,连接db1
  
r1 = redis.Redis(connection_pool=pool1)  # 使用连接池连接,使用连接池一定要在pool中声明db,而不是这里
  
r2 = redis.Redis('192.168.246.11', 6379, db=2)  # 连接db2
  

  
r2.delete('k1', 'k2', 'k3')
  
r1.mset(k1='v1', k2='v2', k3='v3')
  
print(r1.keys(), r2.keys())
  
print(r2.exists('k1'))
  
r1.move('k1', 2)  # 将k1移动到db2
  
print(r1.keys(), r2.keys())
  
print(r2.exists('k1'))
  
r2.rename('k1', 'l1')  # 重命名
  
print(r1.keys(), r2.keys())
  
print(r2.exists('k1'))
  

  randomkey() :随机获取一个redis的name(不删除)
  type(name) :获取name对应值的类型
  同之前 Hash 操作中的 scan 方法相似,用于获取大量数据的方法:
  scan(cursor=0, match=None, count=None)
  scan_iter(match=None, count=None)

管道
  redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次 pipline 是原子性操作。
  

import redis, time  
r3 = redis.Redis('192.168.246.11', 6379, db=3)
  

  
r3.delete('name', 'role')
  
# pipe = r3.pipeline(False)  # 效果和下面一样,看不出是不是原子操作。
  
pipe = r3.pipeline()  # 默认就是True,无论是否是True,都会同时送达。参数是决定是否是原子操作
  

  
pipe.set('name', 'Alex')  # 使用管道进行请求
  
for i in range(10):  # sleep结束前都不会 set name
  print('\r', i, end='', flush=True)
  time.sleep(1)
  
pipe.set('role', 'SB')
  
pipe.execute()
  

发布/订阅
  这里分消息的发布方和订阅方。
  发布消息,建立连接,然后发布消息。每条消息都有消息的频道和内容。
  订阅消息,建立连接,订阅频道。开始接收消息。
  发布方:
  

import redis  
r = redis.Redis('192.168.246.11', 6379)
  
res = r.publish('FM101.7', 'Hello 1')
  
print(res)  # 返回值是订阅者的数量
  
r.publish('SDS.IDX', 'Hello 2')
  
r.publish('alex.python', 'Hello 3')
  
res = r.publish('old.boy', 'Hello 4')  # 这个频道没人订阅
  
print(res)
  

  订阅方:
  

import redis  

  
r = redis.Redis('192.168.246.11', 6379)
  
sub = r.pubsub()
  
sub.subscribe('FM101.7', 'FM103.7')  # 订阅给定的一个或多个频道
  
sub.psubscribe('SDS.*', '*.python')  # 订阅一个或多个符合给定模式的频道
  
msg = sub.parse_response()  # 每订阅一个频道,服务器都会回复一条。
  
print(msg)
  

  
while True:  # 开始接收消息
  msg = sub.parse_response()
  print(msg)
  

  感觉这里以及上面的部分功能(List 操作中阻塞的pop方法)和消息队列有交集,需要的时候选择是个更加合适的系统使用。
  这里讲的比较简单,基本上就是简单过了一遍。还有更多细致的功能,只能去查阅文档资料了。

作业
  作业更新在上一篇里,这篇的内容没作业。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-546863-1-1.html 上篇帖子: 利用python抓取网页图片 下篇帖子: python - 字典
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表