Redis基础

一、Redis介绍

1、redis介绍

开源:早起版本2w3千行

基于键值对的存储系统:字典形式

多种数据结构:字符串,hash,列表,集合,有序集合

高性能,功能丰富

使用的公司有:github,twitter,stackoverflow,阿里,百度,微博,美团,搜狐

2、8个特性:

(1)速度快:10w ops(每秒10w读写),数据存在内存中,c语言实现,单线程模型

(2)持久化:rdb和aof

(3)多种数据结构

                   5大数据结构

                   BitMaps位图:布隆过滤器 本质是 字符串

                   HyperLogLog:超小内存唯一值计数,12kb HyperLogLog 本质是 字符串

                   GEO:地理信息定位 本质是有序集合

(4)支持多种编程语言:基于tcp通信协议,各大编程语言都支持

(5)功能丰富:发布订阅(消息) Lua脚本,事务(pipeline)

(6)简单:源代码几万行,不依赖外部库

(7)主从复制:主服务器和从服务器,主服务器可以同步到从服务器中

(8)高可用和分布式

​                2.8版本以后使用redis-sentinel支持高可用

​                3.0版本以后支持分布式

3、典型使用场景

缓存系统:使用最广泛的就是缓存

计数器:网站访问量,转发量,评论数(文章转发,商品销量,单线程模型,不会出现并发问题)

消息队列:发布订阅,阻塞队列实现(简单的分布式,blpop:阻塞队列,生产者消费者)

排行榜:有序集合(阅读排行,点赞排行,推荐(销量高的,推荐))

社交网络:很多特效跟社交网络匹配,粉丝数,关注数

实时系统:垃圾邮件处理系统,布隆过滤器

二、Redis安装 及配置

1、官网下载,如果没有更改安装路径,就直接下一步就可以了

2、redis相关配置

在安装目录下,找到redis.windows-service.conf,在该文件中进行配置

"""
1)绑定的ip地址,多个ip用空格隔开
bind 127.0.0.1

2)端口,默认6379,一般不做修改
port 6379

3)是否以守护进程启动,默认为no,一般改为yes代表后台启动(windows系统不支持)
daemonize no

4)定义日志级别,默认值为notice,有如下4种取值:
    debug(记录大量日志信息,适用于开发、测试阶段)
    verbose(较多日志信息)
    notice(适量日志信息,使用于生产环境)
    warning(仅有部分重要、关键信息才会被记录)
loglevel notice

5)配置日志文件保持地址,默认打印在命令行终端的窗口上
    如果填写 "./redis.log" 就会在启动redis服务的终端所在目录下,用redis.log记录redis日志
logfile ""

eg)终端首先切断到log文件夹所在目录(一般就可以采用redis的安装目录,也可以自定义),再启动reids服务
logfile "./log/redis.log"

6)数据库个数,默认是16个,没特殊情况,不建议修改
databases 16

7)数据持久化
save 900 1  # 超过900秒有1个键值对操作,会自动调用save完成数据持久化
save 300 10  # 超过300秒有10个键值对操作,会自动调用save完成数据持久化
save 60 10000  # 超过60秒有10000个键值对操作,会自动调用save完成数据持久化

8)数据库持久化到硬盘失败,redis会立即停止接收用户数据,让用户知道redis持久化异常,避免数据灾难发生(重启redis即可),默认为yes,不能做修改
stop-writes-on-bgsave-error yes

9)消耗cpu来压缩数据进行持久化,数据量小,但会消耗cpu性能,根据实际情况可以做调整
rdbcompression yes
10)增持cpu 10%性能销毁来完成持久化数据的校验,可以取消掉
rdbchecksum yes

11)持久化存储的文件名称
dbfilename dump.rdb

12)持久化存储文件的路径,默认是启动服务的终端所在目录
dir ./

13)reids数据库密码
requirepass 密码
"""

三、Redis的基本操作

1、启动服务:

"""
windows系统
1)前台启动
    i)打开终端切换到redis安装目录
    >: cd C:AppsRedis
    
    ii)启动服务
    >: redis-server redis.windows.conf

2)后台启动
    i)打开终端切换到redis安装目录
    >: cd C:AppsRedis
    
    ii)启动服务(后面的配置文件可以省略)
    >: redis-server --service-start redis.windows-service.conf
"""
# linux启动
redis-server

2、连接redis:

"""
1)默认连接:-h默认127.0.0.1,-p默认6379,-n默认0,-a默认无
>: redis-cli

2)完整连接:
>: redis-cli -h ip地址 -p 端口号 -n 数据库编号 -a 密码

3)先连接,后输入密码
>: redis-cli -h ip地址 -p 端口号 -n 数据库编号
>: auth 密码
"""

3、密码设置、修改、查找

"""
1)提倡在配置文件中配置,采用配置文件启动
requirepass 密码

2)当服务启动后,并且连入数据库(redis数据库不能轻易重启),可以再改当前服务的密码(服务重启,密码重置)
config set requirepass 新密码

3)已连入数据库,可以查看当前数据库服务密码
config get requirepass
"""

4、其他操作:

1、切换数据库:
>: select 数据库编号
    
2、关闭服务(前提是数据库已连接)
>: shutdown
# 直接连接数据库并关闭redis服务
>: redis-cli -h ip地址 -p 端口号 -n 数据库编号 -a 密码 shutdown

3、清空redis数据库(前提数据库已连接)
>: flushall
    
4、数据持久化:
1)配置文件默认配置
>: save 900 1  # 超过900秒有1个键值对操作,会自动调用save完成数据持久化
>: save 300 10  # 超过300秒有10个键值对操作,会自动调用save完成数据持久化
>: save 60 10000  # 超过60秒有10000个键值对操作,会自动调用save完成数据持久化

2)安全机制
# 当redis服务不可控宕机,会默认调用一下save完成数据持久化(如果数据量过大,也可能存在部分数据丢失)

3)主动持久化
>: save  # 连入数据库时,主动调用save完成数据持久化

注:数据持久化默认保存文件 dump.rdb,保存路径默认为启动redis服务的当前路径

四、Redis在python中的使用

1、导入依赖库
>: pip3 install redis
2、使用;
import redis
#decode_response=True 得到的结果会自动解码(不是二进制数据)
conn=redis.Redis(host='127.0.0.1',port=6379,db=1,password=密码,decode_responses=True)
#连接池:
pool=redis.ConnectionPool(host='127.0.0.1',port=6379,db=1,max_connections=100,password=密码,decode_responses=True)
conn_pool=redis.Redis(conncetion_pool=pool)

五、Redis数据类型

String类型操作

String类型在内存中的存储是按照一个name对应一个value来存储的

'''
ex:过期时间 (单位:秒)
px: 过期时间 (单位:毫秒)
nx:如果设置为True,则只有name不存在时,set操作才执行,如果name存在,则修改不了,执行没有效果
xx: 如果设置为True,则只有name存在是,set操作才执行,name值存在才能修改,不存在,不会设置新值
'''
conn.set('height','180',ex=1)
conn.set('height',180,px=1)
conn.set('height','100',nx=True)
# height结果:height=180
conn.set('height','100',xx=True)
# height结果:height=100
conn.set('height1','102',xx=True)
# height1结果:None

'''
setnx:只用当key不存在的时候,才会执行,存在,则不会执行 等价于set('height','100',nx=True)
setex(name,time,value) 等价于 set('height','180',ex=1)
psetex(name,time_ms,value) 等价于 conn.set('height',180,px=1)
'''
conn.set('height', '180')
conn.setnx('height', '100')
# 此时height 还是 180
conn.setex('height1',1,'120')
# 等价于set('height',180,px=1)
conn.psetex('height', 1, '110')
# print(conn.get('height'))
print(conn.get('height1'))
'''
mset:以字典的形式插入多个
mget: 返回列表的形式
getset: 设置一个值,并返回一个原来的旧值
'''
# conn.mset({'k1': 'hello', 'k2': 'world'})
conn.mget(['k1', 'k2'])
# 结果:[b'hello',b'world']
re = conn.getset('k1', '111')
# 结果:返回的是k1旧值 :hello


'''
getrange(key,start,end);截取value的长度,类似切片,截取超过本身长度则只取本身
setrange(key,offset,value): 在value的offset起始位置插入value值
getbit('key,offset):截取value的二进制中指定位置的值(0或者1)
setbit(key,offset,value): 将key对应的值的二进制表示的位进行操作,注意value值只能是1或者0 incr('key',amount=1): 只要执行该语句,value数字就会加amount的值,一般用于访问量统计
incrbyfloat(key,amount=1.0): 同incr一样,自增数是浮点型 decr('key',amount=1): 只要执行该语句,value数字就会减1 append('key',insert_value):原来value+insert_value。
bitop(operation,dest,*keys):
operations: AND(并)、OR(或)、NOT(非)、XOR(异或)
dest:新的Redis的key
*key: 要查找的Redis的name
bitcount(key,start=None,end=None): 获取key对应值的二进制中的某位的值
strlen(key): 返回key对应值的字节长度(一个汉字3个字节)
''' ret=conn.getrange('k1',0,3) # 原来k1 = 11111,执行后得到结果是 111, conn.setrange('k4',2,1) # 原来k4=8888 现在变成 k4=88188 print(conn.get('k4')) ret=conn.getbit('k4',3) #结果:ret=1 conn.set('k5',1) conn.incr('k5',2) conn.incr('k5') print(conn.get('k5')) # 结果:k5=4 conn.decr('k5') print(conn.get('k5')) # 结果:k5=2 conn.append('k5','oo') # 结果 k5=200
conn.bitop('AND','k6','k1','k2','k3')

 Hash操作(value是字符类型)

Hash操作,redis中Hash在内存中的存储格式如下:

'''
在对应的hash中设置一个键值对(不存在,则创建,否则,修改)
hset(name,key,value):
    name:redis的name
    key:字典关键字
    value:字典关键字对应的值

hget(name,key): 获取name对应的hash中key对应的值
'''
conn.hset('hash1','h1',11)
conn.hset('hash1','h2',22)
conn.hset('hash1','h1',333)
ret=conn.hget('hash1','h1')
# >: 333
'''
在对应的hash中批量设置键值对
hmset(name,mapping):
    name: redis的name
    mapping: 字典

hmget(name,keys,*args):
    keys:要获取key集合
    *args: 要获取的key
'''
conn.hmset('hash2',{'k1':1,'k2':2,'k3':3})
ret=conn.hmget('hash2','k1','k2','k3')
#两者等价
ret=conn.hmget('hash2',['k1','k2','k3'])
# >:结果都是 ['1','2','3']

'''
hgetall(name): 获取name对应hash的所有键值,以字典的形式返回
'''
ret=conn.hgetall('hash2')
# >: {'k1': '1', 'k2': '2', 'k3': '3'}

'''
hlen(name): 获取name对应的hash中键值对的个数
hkeys(name): 获取name对应的hash中所有key的值,以列表形式返回
hvals(name): 获取name对应hash中所有value的值,以列表形式返回
hexists(name,key): 判断当前hash中是否存在key
hdel(name,*keys): 删除hash中指定的key的键值对
'''
ret=conn.hlen('hash2')
# >: 3
ret=conn.hkeys('hash2')
# >: ['k1', 'k2', 'k3']
ret=conn.hvals('hash2')
# >: ['1', '2', '3']
ret=conn.hexists('hash2','k1')
# >: True
conn.hdel('hash2','k1','k2')
# >: 2

'''
自增name对应的hash中指定key的值,不存在则创建key=amount
hincrby(name,key,amount=1):
       amount: 是自增数(整数)
hincrbyfloat(name,key,amount=1.0) 同hincrby一样,只不过是自增数是浮点类型
'''
conn.hincrby('hash2','k1',amount=1)
conn.hincrby('hash2','k1',amount=1)
conn.hincrbyfloat('hash2','k2',amount=1.1)
conn.hincrbyfloat('hash2','k2',amount=1.1)
# >: hahs2所有键值对:{'k3': '3', 'k1': '2', 'k2': '2.2'}

'''
hscan(name,cursor=0,match=None,count=None):
      cursor: 游标(基于游标分批获取数据)
      match: 匹配指定key,默认None 表示所有的key
      count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
#eg:
# 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
# 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
# ...
# 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
cursor1,data1=conn.hscan('hash2',cursor=0,match=None,count=None)
# >:0 ,{'k3': '3', 'k1': '2', 'k2': '2.2'}

'''
# 利用yield封装hscan创建生成器,实现分批去redis中获取数据
hscan_iter(name,match=None,count=None):
# 参数:
    # match,匹配指定key,默认None 表示所有的key
    # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
for item in conn.hscan_iter('hash2'):
    print(item)
# >: ('k3', '3')
# >: ('k1', '2')
# >: ('k2', '2.2')

List列表操作

在内存中存储方式

'''
lpush(name,values): 在对应的list中添加元素,每个新元素都是添加在列表的最左边
rpush(name,values)则是添加在列表的右边
'''
conn.lpush('l1',11,22,33)
# >: 33,22,11
'''
lpushx(name,value): 跟lpush一样,也是添加元素,
但是,只有当name存在是才会添加,当name不存在时,则不会添加
注意: rpushx则是添加在列表右边
'''
conn.lpushx('l2',1)
conn.lpushx('l1',1)
'''
llen(name): 获取name对应的list元素的个数
'''
conn.llen('l1')
# >: 19
'''
linsert(name,where,refvalue,value):
 参数:
     name,redis的name
     where,BEFORE或AFTER(小写也可以)
     refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
     value,要插入的数据
'''
conn.linsert('l1',where='before',refvalue=1,value=22222)

'''
lset(name,index,value): 在list的某个位置插入一个值
    index: list的索引位置
    value: 要设置的值
    
lrem(name,count,value): 删除name对应list中指定的值
    value: 要删除的值
    count:  count=0,删除列表中所有的指定值;
          count=2,从前到后,删除2个;
          count=-2,从后向前,删除2个
          
lpop(name): 删除name对应list的左侧第一个元素,并返回该元素
rpop:则是右侧第一个元素
'''
conn.lset('l1',2,'1111111111')
conn.lrem('l1',value=11,count=0)
l=conn.lpop('l1')
# >: 22222

'''
lindex(name,index): 返回索引对应的元素
lrange(name,start,end): 跟列表切片一致
ltrim(name,start,end): 在name对应的列表中移除没有在start-end索引之间的值
'''
l= conn.lindex('l1',2)
# >: 22
l=conn.lrange('l1',1,10)
# >: ['1111111111', '22', '33', '22', '33', '22', '33', '22', '33', '22']
conn.ltrim('l1',1,9)
'''
从一个列表取出最右边的元素,同时,将取出来的元素添加至另一个列表的最左边
rpoplpush(src,dst):
     src: 要取数据的列表name
     dst: 要添加数据的列表name
     
同rpoplpush一样,只不过,如果src这个列表没有数据的话,会进入阻塞状态。
brpoplpush(src,dst,timeout=0):
     timeout: 超时时间,0表示永远阻塞
'''
conn.rpoplpush('l1','l2')
'''
获取并移除列表第一个元素,如果列表没有元素,则会计入阻塞,直到发现可弹出元素或者等待超时为止
blpop(keys,timeout):
    keys: redis的name的元素集合
    timeout: 超时时间,默认是0,表示永远阻塞
'''
conn.blpop(('l2','l1'),timeout=2)
# >: ('l1','33')

#自定义增量迭代
# 由于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)

其他操作:

blpop key timeout #lpop的阻塞版,timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1)
brpop key timeout #rpop的阻塞版,timeout是阻塞超时时间,timeout=0为拥有不阻塞 o(1)

#要实现栈的功能
lpush+lpop
#实现队列功能
lpush+rpop
#固定大小的列表
lpush+ltrim
#消息队列
lpush+brpop

Set操作:(不允许重复的列表)

# sadd(name,values) 添加元素,可以添加一个或多个
conn.sadd('s1', 111, 222)

# scard(name) 获取name对应的集合中元素个数
conn.scard('s1')
# >:2
conn.sadd('s2', 111, 333,444,555,666,777)
'''
smembers(name) 获取集合中所有元素
sismember(name,value) 检测value是否是name集合的元素
'''
conn.smembers('s1')
# >:{'111', '222'}

conn.sismember('s1', '111')
# >: True

'''
sdiff(keys,*args) 差集
sdiffstore(dest,keys,*args),将差集存在一个新的集合中
   参数 dest: 是新集合的name
'''
conn.sdiff('s1', 's2')  # 在集合s1中但是不在集合s2中的元素
# >: {'222'}
conn.sdiffstore('s3','s1','s2')
# >: s3={'222'}

'''
sinter(keys,*args) 交集
sinterstore(dest,keys,*args) 将交集结果存在dest中
'''
conn.sinter('s1', 's2')
conn.sinterstore('s3', 's1', 's2')
# >: {'111'}
'''
并集:
sunion(keys,*args)
sunionstore(dest,keys,*args) 并集结果存于dest这个新集合中
'''
conn.sunion('s1','s2')
conn.sunionstore('s3','s1','s2')

'''
smove(src,dst,value):将src集合中的valuse移动到dst集合中
spop(name): 从集合的右侧移除一个成员并将其返回
'''
conn.smove('s1','s2','222')

# srandmember(name,numbers):从集合随机获取 numbers个元素
conn.srandmember('s2', 2)
# >:['111', '333']

# srem(name,values) 删除集合中某些值
conn.srem('s2',111,333)

'''
通哈希类型的hscan一样
sscan(name,cursor=0,match=None,count=None):
      cursor: 游标(基于游标分批获取数据)
      match: 匹配指定key,默认None 表示所有的key
      count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
# eg:
# 第一次:cursor1, data1 = r.sscan('xx', cursor=0, match=None, count=None)
# 第二次:cursor2, data1 = r.sscan('xx', cursor=cursor1, match=None, count=None)
# ...
# 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
conn.sscan('s2', cursor=0, match=None, count=2)
# >: (2, ['555', '111'])

'''
# 利用yield封装sscan创建生成器,实现分批去redis中获取数据
sscan_iter(name,match=None,count=None):
# 参数:
    # match,匹配指定key,默认None 表示所有的key
    # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
for item in conn.sscan_iter('s2',match=None,count=None):
    print(item)
# >:555
# >:111
# >: 333
# ...

有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。(结构:(name, value,score))

'''
有序集合添加元素
zadd(self, name, mapping, nx=False, xx=False, ch=False, incr=False):
参数:
    mapping: 字典
    nx:如果设置为True,则只有name不存在时,set操作才执行,如果name存在,则修改不了,执行没有效果
    xx: 如果设置为True,则只有name存在是,set操作才执行,name值存在才能修改,不存在,不会设置新值
    ch: 如果为True,返回值返回的是修改的元素数。修改的元素包括添加的新元素和分数更改的元素。false则默认返回0
    incr:设置为True时,当集合元素不存在时,则没有影响,若集合元素(比如:n1)存在,则会把原来的元素对应的value值,加新的value值。
'''
conn.zadd('zs1',{'n1':1,'n2':2,'n3':3,'n4':5,'n5':4})
conn.zadd('zs1',{'n1':6},incr=True)
# >: n1=7
'''
name有序集合元素的数量
zcard(name)
'''
conn.zcard('zs1')
# >: 5
'''
 获取name对应的有序集合分数(value) 在[min,max]之间的个数
 zcount(name,min,max):
'''
conn.zcount('zs1',2,5)
# >: 4
'''
有序集合结构:(name,value,score)
 zincrby(name, amount, value):
'''
conn.zincrby('zs1',amount=4,value='n1')
# >: n1 对应的score 从2 变成6
'''
conn.zrange(name, start, end, desc=False, withscores=False,score_cast_func=float)
 参数:
    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)
'''
conn.zrange('zs1',1,5)
# >: ['n3', 'n5', 'n4', 'n1']
conn.zrange('zs1',1,5,withscores=True)
# >: [('n3', 3.0), ('n5', 4.0), ('n4', 5.0), ('n1', 6.0)]

'''
 获取name有序集合中的value的排行位置(本质就是位置,是从0开始计)
 zrank(name,value)
 更多:
    # zrevrank(name, value),从大到小排序
'''
conn.zrank('zs1','n1')
# >: 4
conn.zrevrank('zs1','n1')
# >: 0

'''
 conn.zrangebylex(name, min, max, start=None, num=None)
 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 
 (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)
'''
conn.zrangebylex('zs1','[n1','+')
# >: ['n2', 'n3', 'n5', 'n4', 'n1']

'''
zrem(name,values) 删除name集合中values的值
zremrangebyrank(name,min,max): 根据value范围删除
zremrangebyscore(name,min,max): 根据分数范围删除
zremrangebylex(name, min, max):根据值返回删除
'''
conn.zrem('zs1',['n5','n4'])
conn.zremrangebyrank('zs1',2,3)
conn.zremrangebyscore('zs1',7,9)
'''
获取两个有序集合的交集,存在一个新的集合,如遇到相同值不同分数,则按照aggregate进行操作
zinterstore(dest,keys,aggregate=None)
获取两个有序集合的并集,存在一个新的集合,如遇到相同值不同分数,则按照aggregate进行操作
zunionstore(dest, keys, aggregate=None)
 aggregate的值为:  SUM  MIN  MAX
'''
# zs1={n1:1,n2:2,..} zs2={n1:4,b1:1,..}
conn.zinterstore('zs3',('zs1','zs2'),aggregate='MAX')
# >: zs3={n1:4}
'''
跟字符串的相似
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
zscan_iter(name, match=None, count=None,score_cast_func=float)
    score_casst_func:是用来处理分数的
'''

其他操作

#delete(*names) #删除redis中的任意数据类型
conn.delete('k4','k5')
exists(name) #判断name是否存在
'''
keys(pattern='*') 获取redis的name
# 更多:
    pattern = * 匹配数据库中所有 key 。
    pattern = h?llo 匹配 hello , hallo 和 hxllo 等。
    pattern = h*llo 匹配 hllo 和 heeeeello 等。
    pattern = h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 
'''
conn.keys(pattern='*')
# ['s1', 'zs1', 'zs2', 's3', 's2', 'hash1', 'k1', 'k3', 'hash2', 'name', 'k2', 'zs3', 'l1']

expire(name ,time) # 为某个redis的某个name设置超时时间
rename(src, dst) # 对redis的name(src)重命名为dst
move(name, db)  # 将redis的某个值移动到指定的db下
randomkey() # 随机获取一个redis的name(不删除)
type(name) # 获取name对应值的类型
scan(cursor=0, match=None, count=None)
scan_iter(match=None, count=None) # 同字符串操作,用于增量迭代获取key

redis的总结:

'''
列表:实现timeLine功能,时间轴,微博关注的人,按时间轴排列,在列表中放入关注人的微博的即可
集合:抽奖系统 :通过spop来弹出用户的id,活动取消,直接删除
     点赞,点踩,喜欢等,用户如果点了赞,就把用户id放到该条记录的集合中
     标签:给用户/文章等添加标签,sadd user:1:tags 标签1 标签2 标签3
​     给标签添加用户,关注该标签的人有哪些
     共同好友:集合间的操作
​    sadd:可以做标签相关
​    spop/srandmember:可以做随机数相关
​    sadd/sinter:社交相关
有序集合:做排行榜
'''

六、 管道

管道来实现一次请求执行多条命令,减少多个命令造成的网络时延。

注意:管道是没有原子性的,同时,也不是命令越多越好

# -*-coding:utf-8 -*-
import redis

pool=redis.ConnectionPool(host='127.0.0.1',port=6379,password=12345)
r=redis.Redis(connection_pool=pool)

#transaction=True 开启事务,注意,该事务没有回滚
pip=r.pipeline(transaction=True)
pip.multi() #
pip.set('k4','111')
pip.set('k5','5555')
pip.execute() #执行

1次pipeline(n条命令)=1次网络时间+n次命令时间

'''
pipeline期间将“独占”链接,此期间将不能进行非“管道”类型的其他操作,直到pipeline关闭;
如果你的pipeline的指令集很庞大,为了不干扰链接中的其他操作,你可以为pipeline操作新建Client链接,让pipeline和其他正常操作分离在2个client中。
不过pipeline事实上所能容忍的操作个数,和socket-output缓冲区大小/返回结果的数据尺寸都有很大的关系;
同时也意味着每个redis-server同时所能支撑的pipeline链接的个数,也是有限的,这将受限于server的物理内存或网络接口的缓冲能力
'''

七、事务

事务是一个单独的隔离操作,将事务中的命令进行序列化、按顺序去执行。本质:就是命令入队,按顺序执行。

注意:redis单条命令式是保存原子性,但是redis事务是不保证原子性

multi:开启事务

exec:执行事务

discard:清空事务队列,并放弃执行事务

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> exec  #执行事务
1) OK
2) OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> discard  # 取消事务
OK

八、Django中使用redis

1、方法一(直接使用):

 先封装一个redis_pool.py文件

import redis
POOl=redis.ConnectionPool(host='127.0.0.1',port=6379,password='12345',max_connections=1000)

再在视图函数views中写代码

import redis

from luffy.utils.redis_pool import POOl
def index(request):
    conn=redis.Redis(connection_pool=POOl)
    conn.hset('kkk','age',11)
    ...

2、方法二(使用django-redis模块)

(1)pip install django-redis

(2)setting里配置:

# redis配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/2",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            "PASSWORD": "123",
        }
    }
}

(3)视图函数:

from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))
原文地址:https://www.cnblogs.com/nq31/p/14087899.html