安装说明
业务需求分析
Windows平台:Redis版本老旧,且为微软开发维护,但便于使用以及记录笔记;
虚拟机解决方案:吃电脑性能,但既能写笔记,网页在线,不支持typora,也能直接同时使用IDE;
服务器解决方案:vim写python代码,开两个页面同时开启redis;缺点:无图形化界面,性能占用最低;
双系统方案:物理机满血性能;网页在线笔记,图形化以及双应用同开;缺点:失去社交交互;
成本分析:
虚拟机需要软件本身以及CentOS镜像,下载安装周期最长;物理机省却虚拟机安装时间,成本次之;服务器仅需要安装Redis,成本最低;
4.2 redis
的连接方式
授课笔记:
[Redis数据库]:redis数据库基础篇 - Mr·Yuan - 博客园 (cnblogs.com)
临时连接
import redis
# 01 基本连接方式
r = redis.Redis(host="127.0.0.1", port=6379)
r.set("age", 99)
print(r.get("age")) # b'99'
连接池—持久化连接
# 02 连接池,类似于QuerySet
pool = redis.ConnectionPool(host="127.0.0.1", port=6379)
r = redis.Redis(connection_pool=pool)
4.3Redis
的字符串操作
set
的第三个参数-设置过期时间
set
的第五个参数[条件存储->键]
r.set("info", "Alex", 5, nx=True)
print(r.get("info"))
set
第四个参数px
毫秒过期
r.set("info", "Alex", px=10000)
print(r.get("info"))
set
第五个参数xx
r.set("info", "Alex", xx=True)
print(r.get("info"))
批量写入—逐个读取
r.mset({'k1': 'v1', 'k2': 'v2'})
print(r.get("k1"))
批量写入[mset
]批量读出[mget
]
r.mset({'k1': 'v1', 'k2': 'v2'})
print(r.mget("k1", "k2"))
getrange
对键切片
r.set("info", "Alex")
print(r.getrange("info", 0, 2))
setrange
切片并且替换
setrange(self, name, offset, value) # offset 开端 也就是开始替换的起始点,这个位置取得到,请观察输出
r.set("info", "Alex")
r.setrange("info", 1, "wesome")
print(r.get("info"))
incr
自增加1类似与 +=1
& ++
# 数字与字符串均视为字符串
r.set("age", "100")
r.set("range", 99)
r.incr("age")
print(r.get("age"))
print(r.get("range"))
incr
自增加1类似与 -=1
& –
r.set("age", "100")
r.set("range", 99)
r.decr("age")
print(r.get("age"))
print(r.get("range"))
append
追加 类似于 字符串拼接 比较于 setrange
无需指定起始点
r.set("info", "Alex")
print(r.get("info"))
r.append("info", " & Egon")
print(r.get("info"))
4.7redis
有序集合操作
1 添加以及查询语句
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
# 0 指的是游标的位置,迭代时可能用到;
2 一般计数
计算总数
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
print(r.zcard("z"))
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
4
对区间内键计数—[按照值的方式]
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
print(r.zcount("z", 1, 3))
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
2
3 对集合-键值对中的值进行自增[指定键的方式]
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
r.zincrby("z", 2, "n3")
print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 7.0)])
4 按照位序取键
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))# 对有序集合计数,统计键值对的数量
print(r.zrange("z", 0, 2))
"""
输出
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
[b'n1', b'n2', b'n4']
"""
'''参数说明:
name redis的name
start 有序集合索引起始位置
end 有序集合索引结束位置
desc 排序规则,默认按照分数从小到大排序
withscores 是否获取元素的分数,默认只获取元素的值
score_cast_func 对分数进行数据转换的函数
'''
5 获取键的排序
r.zadd("z", {"n1":1, "n2":2, "n3":5, "n4":4})
print(r.zscan("z"))
print(r.zrank("z", "n4"))
"""
输出:
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
2
"""
6 按照键删除键值对
print(r.zscan("z"))
r.zrem("z", "n2")
print(r.zscan("z"))
'''
输出
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
(0, [(b'n1', 1.0), (b'n4', 4.0), (b'n3', 5.0)])
'''
6.1 按照[键的索引值]排名删除
print(r.zscan("z"))
r.zremrangebyrank("z", 0, 1)
print(r.zscan("z"))
'''
输出:
(0, [(b'n1', 1.0), (b'n4', 4.0), (b'n3', 5.0)])
(0, [(b'n3', 5.0)])
'''
6.2 按照值的大小删除
print(r.zscan("z"))
r.zremrangebyscore("z", 0, 3)
print(r.zscan("z"))
'''
输出:
(0, [(b'n1', 1.0), (b'n2', 2.0), (b'n4', 4.0), (b'n3', 5.0)])
(0, [(b'n4', 4.0), (b'n3', 5.0)])
'''
7 求并集
r.zadd("z1", {"n1": 1, "n2": 2, "n3": 5, "x": 100})
r.zadd("z2", {"n3": 4, "n4": 5, "n5": 6, "x": 100})
r.zunionstore("z3", ("z1", "z2"))
print(r.zscan("z3"))
'''
output:
(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 求交集
r.zadd("z5", {"n1": 1, "n2": 2, "n3": 5, "x": 100})
r.zadd("z6", {"n3": 4, "n4": 5, "n5": 6, "x": 100})
r.zinterstore("z4", ("z5", "z6"))
print(r.zscan("z4"))
'''
output:
(0, [(b'n3', 9.0), (b'n4', 10.0), (b'n5', 12.0), (b'x', 200.0)])
'''
4.8 Redis 的其他操作
获取所有的键
print(r.keys())
对键正则匹配
print(r.keys(pattern="k*"))
删除键
print(r.delete())
判断键是否存在[存在为1,不存在为0]
print(r.exists(""))
对键值对设置过期时间
r.expire("range",10)
print(r.keys())
----------------------
[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']
----------------------
[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']
随机获取一个键
print(r.randomkey())
print(r.keys())
---------------------------
b'z6'
[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']
获取某个键的数据类型
print(r.type("age"))
print(r.keys())
-----------------------
b'string'
[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']
生成器批量获取键
for i in r.scan_iter(match="k*"):
print(i)
---------------------------------
b'k2'
b'k1'
应用场景
1. String
1. 这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存,比如减少库存。
2. 电商库存,利用redis一个特性,单线程无并发;存储JSON字符串
2. hash
1. 这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。
2. 博主在做单点登录的时候就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,
能很好的模拟出类似session的效果。
3. list
1. 使用List的数据结构,可以做简单的消息队列的功能。
2. 可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
3. 本人还用一个场景,很合适---取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
4. set
1. 因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。
2. 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。用户偏好建模
5. sorted set
1. sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
4.7 管道
# 前者是原子性事务,两个创建事务必须同时成功,也就是同进同退
pipe = r.pipeline(transaction=True)
pipe.set('name', 'Alex')
pipe.set('role', 'SB')
pipe.execute()
print(r.keys())
------------------------------------
# 正常的顺序执行,两个语句不会唇齿相依,报错不影响前序代码的执行
r.sadd("mysql", 'I')
xxxxx
r.sadd("How", 'You')
4.8 订阅
基本概念
Redis数据库的特性:多个用户订阅一个键时,当键的值更新,所有用户都可以收到这个更新后的值
类似于微博大V更新,推送给所有粉丝,但由于有些粉丝不在线,因此就投入消息队列,在线后再推送,服务器负载就会降低;
consumer
import redis
r = redis.Redis(host='127.0.0.1')
pub = r.pubsub()
pub.subscribe("fm104.5")
pub.parse_response()
while 1:
msg = pub.parse_response()
print(msg)
producer
import redis
r = redis.Redis(host='127.0.0.1')
r.publish("fm104.5", "Hi Alex")