目录
一:初识Redis
1.什么是Redis
2.Redis的特性(8个)
①速度快
②持久化
③多种数据结构
④支持多种编程语言
⑤功能丰富
⑥简单
⑦主从复制
⑧高可用和分布式
3.Redis的典型使用场景
4.Redis的安装
安装教程:Redis安装教程 - 轻描丨淡写 - 博客园
5.启动的3种方式
①最简启动
②动态参数启动
③配置文件启动
二:再遇Redis
1.Python操作Redis - 普通连接
2. Python操作Redis - 连接池
三:又见Redis
1.String字符串操作
3.n操作redis连接池pytho
3.hash哈希操作
4.set集合操作
5.zset有序集合操作
四:深入Redis
1.其他操作
2.管道
3.Django中使用redis
方式一
方式二
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
开源:早起版本2w3千行
基于键值对的存储系统:字典形式
多种数据结构:字符串,hash,列表,集合,有序集合
高性能,功能丰富
1.10W OPS(每秒操作数10W,实测6W左右)
2.数据存在内存中(内存读写速度高达40~50G/s)
3.c语言实现,单线程模型
为什么Redis速度这么快?
1.单线程单进程,避免了进程线程间的切换
2.IO的多路复用
3.是内存数据库,读写速度快
Redis有RDB和AOF机制
RDB其实就是把数据以快照的形式保存在磁盘上。什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。按照定时操作保存你的数据,这样能够保证数据的安全性
全量备份总是耗时的,有时候我们提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。
但是在一般的情况下,就是快照和AOF同时使用,这样子的话就比较高校和安全地去保存数据,在你操作的时候你可以配置配置文件来生成AOF,rdb文件这样的话,只需要拿到你这两个数据你就可以把操作的数据基本全部拿到。
str:字符串类型 - 接口缓存
list:列表 - 分布式
hash:哈希(相当于Python中的字典) - 缓存
set:集合 - 去重
zset:有序的 - 排行榜
常用的redis命令
keys* 查看当前库所有key(匹配:keys*1)exists key 判断某个key是否存在
type key 查看你的key是什么类型
del key 删除指定的key数据
unlink key 根据value选择非阻塞删除
仅将 keys 从 keyspace元数据中删除,真正的删除会在后续异步操作
expire key 10 10秒钟:为给定的key设置过期时间
ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已经过期
select 命令切换数据库
dbsize 查看当前数据库的key数量
flushdb 清空当前库
flushall 通杀全部库
二、常用的五大数据类型
Redis字符串(String)最大512MB添加 set key value
查看 get key
append key value 将给定的value追加到原值的末尾
strlen key 获得值的长度
setnx key value 只有在key不存在时 设置key的值
incr key 将key中存储的数字值增1,只能对数字值操作,如果为空,新增值为1
decr key 将key中存储的数字值减1
incrby / decrby key 步长 将key中存储的数字值增减。自定义步长**(redis中incr是原子性操作,单线程的)**
mset key1 value1 key2 value2 同时设置一个或多个 key-value对
mget key1 key2 key3 同时获取一个或多个value
msetnx key1 value1 key2 value2 当且仅当所有key不存在 (原子性:又一个失败都失败)
getrange key 起始位置 结束位置 全闭
Redis列表(List)
lpush/rpush key value1 value2 vaule3 从左边/右边插入一个或多个值
lpop/rpop key 从左边/右边吐出一个值。值在健在,值光键亡
rpoplpush key1 key2 从key1列表右边吐出一个值,插到key2列表左边
lrange key start stop
Redis集合(Set)set无序排重
sadd key value1 value2… 将一个或多个member元素加入到集合key中,已经存在的member元素将被忽略
smembers key 取出该集合的所有值
sismember key value 判断集合key是否含有该value值,有1,没有0
scard key 返回该集合的元素个数
srem key value1 value2 删除集合中的某个元素
spop key 随机从该集合中吐出一个值
srandmember key n 随机从该集合取出n个值。不会从集合中删除
smove source destination value 把集合中一个值从一个集合移动到另一个集合
Redis哈希(Hash)
hset key field value 给key集合中的 field键赋值value
hget key1 filed 从key1集合field取出value
hmset key1 field1 value1 field2 value2 批量设置hash的值
hexists key1 field 查看哈希表 key 中,给定域 field是否存在
hkeys key 列出该hash集合的所有field
hvals key 列出该hash集合的所有value
hincrby key field increment 为哈希表 key 中的域field的值加上增量1 -1
hsetnx key field value 将哈希表key中的域field的值设置为value,当且仅当域field不存在
Reids有序集合Zset
zadd key score1 value1 score2 value2 将一个或多个member元素及其score值加入到有序集key当中
zrange key start stop 【WITHSCORES】 返回有序集key中,下标在start stop之间的元素
带withscores,可以让分数一起和值返回到结果集
zrangebyscore key minmax [withscores] [limit offset count]
返回有序集key中,所有score值介于min和max之间(包括等于min或max)的成员
有序集成员按score值递增次序排列
zrevrangebyscore key maxmin [withscores] [limit offset count]
同上,改为从大到小排序
zincrby key increment value 为元素的score加上增量
zrem key value 删除该集合下,指定值的元素
zcount key min max 统计该集合,分数区间内的元素个数
zrank key value 返回该值在集合中的排名,从0开始
————————————————
版权声明:本文为CSDN博主「走,我们去吹风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_51991615/article/details/124183045
基于TCP通信协议,各大编程语言都支持
发布订阅(消息) Lua脚本,事务(pipeline)等
源代码几万行,不依赖外部库
主服务器和从服务器,主服务器可以同步到从服务器中
2.8版本以后使用redis-sentinel支持高可用
3.0版本以后支持分布式
缓存系统: 使用最广泛的就是缓存
计数器: 网站访问量,转发量,评论数(文章转发,商品销量,单线程模型,不会出现并发问题)
消息队列: 发布订阅,阻塞队列实现(简单的分布式,blpop:阻塞队列,生产者消费者)
排行榜: 有序集合(阅读排行,点赞排行,推荐(销量高的,推荐))
社交网络: 很多特效跟社交网络匹配,粉丝数,关注数
实时系统: 垃圾邮件处理系统,布隆过滤器
redis-server
ps -ef|grep redis #查看进程
netstat -antpl|grep redis #查看端口
redis-cli -h ip -p port ping #命令查看
redis-serve --port 6380 #启动,监听6380端口
配置文件启动(6379对应手机按键MERZ,意大利女歌手Alessia Merz的名字)
##通过redis-cli连接,输入config get * 可以获得默认配置
#在redis目录下创建config目录,copy一个redis.conf文件
#daemonize--》是否是守护进程启动(no|yes)
#port---》端口号
#logfile--》redis系统日志
#dir--》redis工作目录
pip安装redis
pip3 install redis
from redis import Redis
conn=Redis(host='127.0.0.1', port=6379)
ret=conn.get('name')
print(ret)
t_redis_pool.py
中
import redis
# pool必须是单例的
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=100) # 造一个池子,最多能放100个连接
t_redis_conn.py
中
import redis
# 包内的py文件,如果想右键运行,导包的时候不能带点
from t_redis_pool import POOL # pycharm提示的错
r = redis.Redis(connection_pool=POOL) # 只要执行这一句话,就是从池中拿出一个连接
ret=r.get('name')
print(ret)
须知:在Redis中设置值,默认,不存在则创建,存在则修改
set(name, value,ex=None, px=None, nx=False, xx=False, keepttl=False)
name:key的名字
value:key的值
ex:过期时间(秒)
px:过期时间(毫秒)
nx:如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx:如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
set('name', 'xxq') # 如果存在,就会覆盖,返回:True;不存在,则无变化,返回:None
set('name', 'xxq', 3) # 设置过期时间为3秒,返回:True;不存在,则无变化,返回:None
set('name1', 'xxq',nx=True) # 如果不存在,就创建并赋值,返回:True;如果存在,则无变化,返回:None
set('name', 'xxq', xx=True) # 存在就覆盖,返回True;不存在,则无变化,返回:None
相当于:set(key, value, nx=True)
psetex('name', 'xxq') # 如果存在,就会覆盖,返回:True;不存在,则无变化,返回:None
相当于:set(key, value, time)
psetex('name', 5, 'xxq') # 如果存在,就会覆盖,返回:True;不存在,则无变化,返回:None
相当于:set(key, time, value, ex=True)
psetex('name', 5000, 'xxq') # 如果存在,就会覆盖,返回:True;不存在,则无变化,返回:None
相当于:set(key, value, ex=True)
mset({'name':'xxq', 'age':'18'}) # 存在就覆盖,不存在就创建,都返回:True
mset(name='xxq', age='18')
res = conn.setrange('name', 3, '111') # 存在则会替换'name'中所有为3的字符为'111';不存在则会创建'name'
name,redis的name
offset,位的索引(将值变换成二进制后再进行索引)
value,值只能是 1 或 0
注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:01100110 01101111 01101111
所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
get(name)
name:key的名字
get('age') # 存在则返回'age'的值:b'18';不存在则返回:None
mget('name', 'age') # 存在就返回一个列表:[b'xxq1', b'18'],不存在就返回:[None, None]
res = conn.mget(['name11', 'age11']) # 存在就返回一个列表:[b'xxq1', b'18'],不存在就返回:[None, None]
getset('name', 'zsy') # 存在就返回原值:b'xxq1',不存在就返回:None
start
和end
都是下标索引,区间是前闭后闭getrange('name', 0, 1) # 存在则返回:b'zs'(name的索引为0和1所在的字符);不存在则返回:b''
获取name对应的值的二进制表示中的某位的值 (0或1)
key,Redis的name
start,位起始位置
end,位结束位置
operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
dest, 新的Redis的name
*keys,要查找的Redis的name
# 如:
bitop("AND", 'new_name', 'n1', 'n2', 'n3')
# 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
返回name对应值的字节长度(一个汉字3个字节)
name,Redis的name
amount,自增数(必须是整数,可以是负数)
# 注:同incrby
name,Redis的name
amount,自增数(浮点型)
name,Redis的name
amount,自减数(整数)
key, redis的name
value, 要追加的字符串
lpush('left', 1, 2, 3, 4) # 创建'left',添加顺序为1 2 3 4,最先添加的会被挤到最后
链表内顺序为:
4
3
2
1
rpush('right', 1, 2, 3, 4) # 创建'right',添加顺序为1 2 3 4,最先添加的会排在最前面
链表内顺序为:
1
2
3
4
llen('left') # 如果存在,则返回:4,;如果不存在,则返回:0
name:redis的name
where:before或after(大小写皆可)
refvalue:标杆值,即被插入对象:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
value:要插入的数据
linsert('left', 'before', 4, 666) # 存在,则在链表'left'的第一个'4'前面插入'666',返回链表总行数;不存在则无变化;返回:0
lset('left', 0, 4) # 存在,则把'left'中的第一个值替换成'4';不存在则报错
name,redis的name
value,要删除的值
count,count=0,删除列表中所有的指定值;
count>0,从前往后删除列表中的个数
count<0,从后往前删除列表中的个数
lpop('left') # 如果存在,则返回:b'1';不存在则返回:None
rpop('left') # 如果存在,则返回:b'4';不存在则返回:None
lindex('left', 3) # 如果存在,则返回:'b2';不存在则返回:None
lrange('left', 2, 4) # 存在则返回列表:[b'3', b'2', b'1'];不存在则返回:[]
name,redis的name
start,索引的起始位置
end,索引结束位置(大于列表长度,则代表不移除任何)
src,要取数据的列表的name
dst,要添加数据的列表的name
src,取出并要移除元素的列表对应的name
dst,要插入元素的列表对应的name
timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
# 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
# 1、获取name对应的所有列表
# 2、循环列表
# 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:
import redis
conn=redis.Redis(host='127.0.0.1',port=6379)
# conn.lpush('test',*[1,2,3,4,45,5,6,7,7,8,43,5,6,768,89,9,65,4,23,54,6757,8,68])
# conn.flushall()
def scan_list(name,count=2):
index=0
while True:
data_list=conn.lrange(name,index,count+index-1)
if not data_list:
return
index+=count
for item in data_list:
yield item
print(conn.lrange('test',0,100))
for item in scan_list('test',5):
print('---')
print(item)
hset('hash1', 'name', 'xxq') # 不存在则创建,返回:1;存在则覆盖,并返回:0
hmset('hash2',{'key1':'value1','key2':'value2'}) # 不存在则创建,返回:1;存在则覆盖,并返回:0
hget('hash1', 'name') # 存在则返回查询到的value;不存在则返回:None
hmget('hash1', 'name1', 'name2') # 存在则返回列表:[b'xxq', b'xxq'];不存在则返回:[None, None]
hmget('hash1', ['name1', 'name2']) # 存在则返回列表:[b'xxq', b'xxq'];不存在则返回:[None, None]
hgetall('hash1') # 若存在,则返回列表:{b'name': b'xxq11', b'name1': b'xxq', };若不存在,则返回:{}
hlen('hash')
hkeys('hash')
hvals('hash')
hexists('hash')
# 将name对应的hash中指定key的键值对删除
print(re.hdel('xxx','sex','name'))
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(整数)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(浮点数)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
# 参数:
# name,redis的name
# cursor,游标(基于游标分批取获取数据)
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
# 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
# ...
# 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# for item in r.hscan_iter('xx'):
# print item
sadd(name,values)
# name对应的集合中添加元素
scard(name)
获取name对应的集合中元素个数
sdiff(keys, *args)
在第一个name对应的集合中且不在其他name对应的集合的元素集合
sdiffstore(dest, keys, *args)
# 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
sinter(keys, *args)
# 获取多一个name对应集合的并集
sinterstore(dest, keys, *args)
# 获取多一个name对应集合的并集,再讲其加入到dest对应的集合中
sismember(name, value)
# 检查value是否是name对应的集合的成员
smembers(name)
# 获取name对应的集合的所有成员
smove(src, dst, value)
# 将某个成员从一个集合中移动到另外一个集合
spop(name)
# 从集合的右侧(尾部)移除一个成员,并将其返回
srandmember(name, numbers)
# 从name对应的集合中随机获取 numbers 个元素
srem(name, values)
# 在name对应的集合中删除某些值
srem(name, values)
# 在name对应的集合中删除某些值
sunion(keys, *args)
# 获取多一个name对应的集合的并集
sunionstore(dest,keys, *args)
# 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中
sscan(name, cursor=0, match=None, count=None)
sscan_iter(name, match=None, count=None)
# 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
zadd(name, *args, **kwargs)
# 获取name对应的有序集合元素的数量
# 获取name对应的有序集合中分数 在 [min,max] 之间的个数
# 自增name对应的有序集合的 name 对应的分数
# 按照索引范围获取name对应的有序集合的元素
# 参数:
# name,redis的name
# start,有序集合索引起始位置(非分数)
# end,有序集合索引结束位置(非分数)
# desc,排序规则,默认按照分数从小到大排序
# withscores,是否获取元素的分数,默认只获取元素的值
# score_cast_func,对分数进行数据转换的函数
# 更多:
# 从大到小排序
# zrevrange(name, start, end, withscores=False, score_cast_func=float)
# 按照分数范围获取name对应的有序集合的元素
# 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)
zrank(name, value)
# 获取某个值在 name对应的有序集合中的排行(从 0 开始)
# 更多:
# zrevrank(name, value),从大到小排序
# 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员
# 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大
# 参数:
# name,redis的name
# min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
# min,右区间(值)
# start,对结果进行分片处理,索引位置
# num,对结果进行分片处理,索引后面的num个元素
# 如:
# ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
# r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']
# 更多:
# 从大到小排序
# zrevrangebylex(name, max, min, start=None, num=None)
# 删除name对应的有序集合中值是values的成员
# 如:zrem('zz', ['s1', 's2'])
# 根据排行范围删除
# 根据分数范围删除
# 根据值返回删除
# 获取name对应有序集合中 value 对应的分数
# 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
# 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
# aggregate的值为: SUM MIN MAX
# 同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作
# 根据删除redis中的任意数据类型
# 检测redis的name是否存在
# 根据模型获取redis的name
# 更多:
# KEYS * 匹配数据库中所有 key 。
# KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
# KEYS h*llo 匹配 hllo 和 heeeeello 等。
# KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
# 为某个redis的某个name设置超时时间
# 对redis的name重命名为
# 将redis的某个值移动到指定的db下
# 随机获取一个redis的name(不删除)
# 获取name对应值的类型
# 同字符串操作,用于增量迭代获取key
redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作
utils文件夹下,建立redis_pool.py
import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,password='123456',max_connections=1000)
视图函数中:
import redis
from django.shortcuts import render,HttpResponse
from utils.redis_pool import POOL
def index(request):
conn = redis.Redis(connection_pool=POOL)
conn.hset('kkk','age',18)
return HttpResponse('设置成功')
def order(request):
conn = redis.Redis(connection_pool=POOL)
conn.hget('kkk','age')
return HttpResponse('获取成功')
安装django-redis模块
pip3 install django-redis
# redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}
# "PASSWORD": "123",
}
}
}
视图函数中:
from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))