安装说明

业务需求分析

Windows平台:Redis版本老旧,且为微软开发维护,但便于使用以及记录笔记;

虚拟机解决方案:吃电脑性能,但既能写笔记,网页在线,不支持typora,也能直接同时使用IDE;

服务器解决方案:vim写python代码,开两个页面同时开启redis;缺点:无图形化界面,性能占用最低;

双系统方案:物理机满血性能;网页在线笔记,图形化以及双应用同开;缺点:失去社交交互;

成本分析:

虚拟机需要软件本身以及CentOS镜像,下载安装周期最长;物理机省却虚拟机安装时间,成本次之;服务器仅需要安装Redis,成本最低;

4.2 redis的连接方式

授课笔记:

[Redis数据库]:redis数据库基础篇 - Mr·Yuan - 博客园 (cnblogs.com)

临时连接

  1. import redis
  2. # 01 基本连接方式
  3. r = redis.Redis(host="127.0.0.1", port=6379)
  4. r.set("age", 99)
  5. print(r.get("age")) # b'99'

连接池—持久化连接

  1. # 02 连接池,类似于QuerySet
  2. pool = redis.ConnectionPool(host="127.0.0.1", port=6379)
  3. r = redis.Redis(connection_pool=pool)

4.3Redis的字符串操作

set的第三个参数-设置过期时间

Redis缓存数据库 - 图1

set的第五个参数[条件存储->键]

  1. r.set("info", "Alex", 5, nx=True)
  2. print(r.get("info"))

Redis缓存数据库 - 图2

set第四个参数px毫秒过期

  1. r.set("info", "Alex", px=10000)
  2. print(r.get("info"))

Redis缓存数据库 - 图3

set第五个参数xx

  1. r.set("info", "Alex", xx=True)
  2. print(r.get("info"))

Redis缓存数据库 - 图4

批量写入—逐个读取

  1. r.mset({'k1': 'v1', 'k2': 'v2'})
  2. print(r.get("k1"))

Redis缓存数据库 - 图5

批量写入[mset]批量读出[mget]

  1. r.mset({'k1': 'v1', 'k2': 'v2'})
  2. print(r.mget("k1", "k2"))

Redis缓存数据库 - 图6

getrange对键切片

  1. r.set("info", "Alex")
  2. print(r.getrange("info", 0, 2))

Redis缓存数据库 - 图7

setrange切片并且替换

  1. setrange(self, name, offset, value) # offset 开端 也就是开始替换的起始点,这个位置取得到,请观察输出
  2. r.set("info", "Alex")
  3. r.setrange("info", 1, "wesome")
  4. print(r.get("info"))

Redis缓存数据库 - 图8

Redis缓存数据库 - 图9

incr自增加1类似与 +=1 & ++

  1. # 数字与字符串均视为字符串
  2. r.set("age", "100")
  3. r.set("range", 99)
  4. r.incr("age")
  5. print(r.get("age"))
  6. print(r.get("range"))

Redis缓存数据库 - 图10

incr自增加1类似与 -=1 &

  1. r.set("age", "100")
  2. r.set("range", 99)
  3. r.decr("age")
  4. print(r.get("age"))
  5. print(r.get("range"))

Redis缓存数据库 - 图11

append 追加 类似于 字符串拼接 比较于 setrange 无需指定起始点

  1. r.set("info", "Alex")
  2. print(r.get("info"))
  3. r.append("info", " & Egon")
  4. print(r.get("info"))

Redis缓存数据库 - 图12

4.7redis 有序集合操作

1 添加以及查询语句

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))
  3. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  4. # 0 指的是游标的位置,迭代时可能用到;

2 一般计数

计算总数

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
  3. print(r.zcard("z"))
  4. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  5. 4

对区间内键计数—[按照值的方式]

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
  3. print(r.zcount("z", 1, 3))
  4. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  5. 2

3 对集合-键值对中的值进行自增[指定键的方式]

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
  3. r.zincrby("z", 2, "n3")
  4. print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
  5. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  6. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 7.0)])

4 按照位序取键

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
  3. print(r.zrange("z", 0, 2))
  4. """
  5. 输出
  6. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  7. [b'n1', b'n2', b'n4']
  8. """
  9. '''参数说明:
  10. name redis的name
  11. start 有序集合索引起始位置
  12. end 有序集合索引结束位置
  13. desc 排序规则,默认按照分数从小到大排序
  14. withscores 是否获取元素的分数,默认只获取元素的值
  15. score_cast_func 对分数进行数据转换的函数
  16. '''

5 获取键的排序

  1. r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
  2. print(r.zscan("z"))
  3. print(r.zrank("z", "n4"))
  4. """
  5. 输出:
  6. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  7. 2
  8. """

6 按照键删除键值对

  1. print(r.zscan("z"))
  2. r.zrem("z", "n2")
  3. print(r.zscan("z"))
  4. '''
  5. 输出
  6. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  7. (0, [(b'n1', 1.0), (b'n4', 4.0), (b'n3', 5.0)])
  8. '''

6.1 按照[键的索引值]排名删除

  1. print(r.zscan("z"))
  2. r.zremrangebyrank("z", 0, 1)
  3. print(r.zscan("z"))
  4. '''
  5. 输出:
  6. (0, [(b'n1', 1.0), (b'n4', 4.0), (b'n3', 5.0)])
  7. (0, [(b'n3', 5.0)])
  8. '''

6.2 按照值的大小删除

  1. print(r.zscan("z"))
  2. r.zremrangebyscore("z", 0, 3)
  3. print(r.zscan("z"))
  4. '''
  5. 输出:
  6. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
  7. (0, [(b'n4', 4.0), (b'n3', 5.0)])
  8. '''

7 求并集

  1. r.zadd("z1", {"n1": 1, "n2": 2, "n3": 5, "x": 100})
  2. r.zadd("z2", {"n3": 4, "n4": 5, "n5": 6, "x": 100})
  3. r.zunionstore("z3", ("z1", "z2"))
  4. print(r.zscan("z3"))
  5. '''
  6. output:
  7. (0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 5.0), (b'n5', 6.0), (b'n3', 9.0), (b'x', 200.0)])
  8. '''

8 求交集

  1. r.zadd("z5", {"n1": 1, "n2": 2, "n3": 5, "x": 100})
  2. r.zadd("z6", {"n3": 4, "n4": 5, "n5": 6, "x": 100})
  3. r.zinterstore("z4", ("z5", "z6"))
  4. print(r.zscan("z4"))
  5. '''
  6. output:
  7. (0, [(b'n3', 9.0), (b'n4', 10.0), (b'n5', 12.0), (b'x', 200.0)])
  8. '''

4.8 Redis 的其他操作

获取所有的键

print(r.keys())

对键正则匹配

print(r.keys(pattern="k*"))

删除键

print(r.delete())

判断键是否存在[存在为1,不存在为0]

print(r.exists(""))

对键值对设置过期时间

  1. r.expire("range",10)
  2. print(r.keys())
  3. ----------------------
  4. [b'z10', b'z3', b'z0', b'z2', b'z5', b'z1', b'z7', b'z', b'k2', b'z4', b'k1', b'info', b'age', b'z6']
  5. ----------------------
  6. [b'z10', b'z3', b'z0', b'z2', b'z5', b'z1', b'z7', b'z', b'k2', b'z4', b'k1', b'age', b'z6']

随机获取一个键

  1. print(r.randomkey())
  2. print(r.keys())
  3. ---------------------------
  4. b'z6'
  5. [b'z10', b'z3', b'z0', b'z2', b'z5', b'z1', b'z7', b'z', b'k2', b'z4', b'k1', b'age', b'z6']

获取某个键的数据类型

  1. print(r.type("age"))
  2. print(r.keys())
  3. -----------------------
  4. b'string'
  5. [b'z10', b'z3', b'z0', b'z2', b'z5', b'z1', b'z7', b'z', b'k2', b'z4', b'k1', b'age', b'z6']

生成器批量获取键

  1. for i in r.scan_iter(match="k*"):
  2. print(i)
  3. ---------------------------------
  4. b'k2'
  5. b'k1'

应用场景

  1. 1. String
  2. 1. 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存,比如减少库存。
  3. 2. 电商库存,利用redis一个特性,单线程无并发;存储JSON字符串
  4. 2. hash
  5. 1. 这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。
  6. 2. 博主在做单点登录的时候就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,
  7. 能很好的模拟出类似session的效果。
  8. 3. list
  9. 1. 使用List的数据结构,可以做简单的消息队列的功能。
  10. 2. 可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
  11. 3. 本人还用一个场景,很合适---取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
  12. 4. set
  13. 1. 因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。
  14. 2. 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。用户偏好建模
  15. 5. sorted set
  16. 1. sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。

4.7 管道

  1. # 前者是原子性事务,两个创建事务必须同时成功,也就是同进同退
  2. pipe = r.pipeline(transaction=True)
  3. pipe.set('name', 'Alex')
  4. pipe.set('role', 'SB')
  5. pipe.execute()
  6. print(r.keys())
  7. ------------------------------------
  8. # 正常的顺序执行,两个语句不会唇齿相依,报错不影响前序代码的执行
  9. r.sadd("mysql", 'I')
  10. xxxxx
  11. r.sadd("How", 'You')

4.8 订阅

基本概念

Redis数据库的特性:多个用户订阅一个键时,当键的值更新,所有用户都可以收到这个更新后的值

类似于微博大V更新,推送给所有粉丝,但由于有些粉丝不在线,因此就投入消息队列,在线后再推送,服务器负载就会降低;

consumer

  1. import redis
  2. r = redis.Redis(host='127.0.0.1')
  3. pub = r.pubsub()
  4. pub.subscribe("fm104.5")
  5. pub.parse_response()
  6. while 1:
  7. msg = pub.parse_response()
  8. print(msg)

producer

  1. import redis
  2. r = redis.Redis(host='127.0.0.1')
  3. r.publish("fm104.5", "Hi Alex")

实现效果

Redis缓存数据库 - 图13