Redis

redis的配置

sudo cat /etc/redis/redis.conf

redis 安装成功以后,window下的配置文件保存在软件 安装目录下,如果是mac或者linux,则默认安装/etc/redis/redis.conf

3.2.1 redis的核心配置选项

redis与mysql类似,也是C/S架构的软件,所以存在客户端和服务端,默认的redis的服务端时redis-server,默认提供的redis客户端是redis-cli。

绑定ip:如果需要远程访问,可将此注释,或绑定1个真实ip

bind 127.0.0.1

端⼝,默认为6379

port 6379

是否以守护进程运行 [windows下需要设置]

  • 如果以守护进程运行,则不会在命令阻塞,类似于服务
  • 如果以守护进程运行,则当前终端被阻塞
  • 设置为yes表示守护进程,设置为no表示⾮守护进程
  • 推荐设置为yes
daemonize yes

RDB持久化的备份文件

dbfilename dump.rdb

RDB持久化数据库数据文件的所在目录

dir /var/lib/redis

日志等级和日期文件的所在目录

loglevel notice
logfile /var/log/redis/redis-server.log

进程ID文件

pidfile /var/run/redis/redis-server.pid

数据库,默认有16个,数据名是不能自定义的,只能是0-15之间,当然这个15是数据库数量-1

database 16

redis的登录密码,生产阶段打开,开发阶段避免麻烦,一般都是注释的。

# requirepass foobared

注意:开启了以后,redis-cli终端下使用 auth 密码来认证登录。

RDB持久化的备份频率,文件格式是二进制

save 900 1
save 300 10
save 60 10000

RDB持久化备份文件的文件名和路径

dbfilename dump.rdb
dir /var/lib/redis

AOF持久化的开启配置项,默认是no关闭的。备份的文件格式:文本格式

appendonly no

AOF持久化的备份文件,存储路径与RDB备份文件路径是一致的。

appendfilename "appendonly.aof"

AOF持久化备份的频率[时间]

# appendfsync always   # 每次修改键对应数据时都会触发一次aof
appendfsync everysec    # 每秒备份,工作中最常用。
# appendfsync no

一主二从三哨兵

3.2.2 Redis的使用

redis是一款基于CS架构的数据库,所以redis有客户端redis-cli,也有服务端redis-server。

其中,客户端可以使用python等编程语言,也可以终端下使用命令行工具管理redis数据库,甚至可以安装一些别人开发的界面工具,例如:RDM。

redis-cli客户端连接服务器:

# redis-cli -h `redis服务器ip` -p `redis服务器port`
redis-cli -h 10.16.244.3 -p 6379 -a 123456

3.3 redis数据类型

redis就是一个全局的大字典,key就是数据的唯一标识符。根据key对应的值不同,可以划分成5个基本数据类型。
1. string类型:
	字符串类型,是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,也就是byte类型。
	单个数据的最大容量是512M。
		key: b"值"
	
2. hash类型:
	哈希类型,用于存储对象/字典,对象/字典的结构为键值对。key、域、值的类型都为string。域在同一个hash中是唯一的。
		key:{
            域(属性): 值,
            域:值,            
            域:值,
            域:值,
            ...
		}
3. list类型:
	列表类型,它的子成员类型为string。
		key: [ 值1,值2, 值3..... ]
4. set类型:
	无序集合,它的子成员类型为string类型,元素唯一不重复,没有修改操作。
		key: {值1, 值4, 值3, ...., 值5}

5. zset类型(sortedSet):
	有序集合,它的子成员值的类型为string类型,元素唯一不重复,没有修改操作。权重值1从小到大排列。
		key: {
			权重值1(数字) 值1;
			权重值22;
			权重值33;
			权重值44;
		}

redis中的所有数据操作,如果设置的键不存在则为添加,如果设置的键已经存在则修改

3.4 string

设置键值

set 设置的数据没有额外操作时,是不会过期的。

set key value

设置键为name值为xiaoming的数据

set name xiaoming

设置一个键,当键不存在时才能设置成功,用于一个变量只能被设置一次的情况。

setnx  key  value

一般用于给数据加锁

127.0.0.1:6379> setnx goods_1 101
(integer) 1
127.0.0.1:6379> setnx goods_1 102
(integer) 0  # 表示设置不成功

127.0.0.1:6379> del goods_1
(integer) 1
127.0.0.1:6379> setnx goods_1 102
(integer) 1

设置键值的过期时间

redis中可以对一切的数据进行设置有效期。

以秒为单位

setex key seconds value

设置键为name值为xiaoming过期时间为20秒的数据

setex name 20 xiaoming

使用set设置的数据会永久存储在redis中,如果实用setex对同名的key进行设置,可以把永久有效的数据设置为有时间的临时数据。

设置多个键值

mset key1 value1 key2 value2 ...

例3:设置键为a1值为python、键为a2值为java、键为a3值为c

mset a1 python a2 java a3 c
mget a1 a2 a3

字符串拼接值

append key value

向键为a1中拼接值haha

append title "我的"
append title "redis"
append title "学习之路"

根据键获取值

根据键获取值,如果不存在此键则返回nil,相当于python的None

get key

获取键name的值

get name

根据多个键获取多个值

mget key1 key2 ...

获取键a1、a2、a3的值

mget a1 a2 a3

自增自减

set id 1
incr id   # 相当于id+1
get id    # 2
incr id   # 相当于id+1
get id    # 3


set goods_id_1 10
decr goods_id_1  # 相当于 id-1
get goods_id_1    # 9
decr goods_id_1   # 相当于id-1
get goods_id_1    # 8

获取字符串的长度

set name xiaoming
strlen name  # 8 

比特流操作

签到记录

8位就是1byte ==> 0010 0100

BITCOUNT   # 统计字符串被设置为1的bit数.
BITPOS     # 返回字符串里面第一个被设置为1或者0的bit位。
SETBIT     # 设置一个bit数据的值 
GETBIT     # 获取一个bit数据的值
SETBIT mykey 7 1   
# 00000001
getbit mykey 7
# 00000001
SETBIT mykey 4 1   # 设置第4个为1
# 00001001
SETBIT mykey 15 1
# 0000100100000001
BITCOUNT mykey
# 3
BITPOS mykey 1
# 4

3.5 key操作

redis中所有的数据都是通过key(键)来进行操作,这里我们学习一下关于任何数据类型都通用的命令。

查找键

参数支持简单的正则表达式

keys pattern

查看所有键

keys *

例子:

# 查看名称中包含`a`的键
keys *a*
# 查看以a开头的键
keys a*
# 查看以a结尾的键
keys *a
# 数字结尾
keys *[1-9]

判断键是否存在

如果存在返回1,不存在返回0

exists key1

判断键title是否存在

exists title

查看键的数据类型

type key

# string    字符串
# hash      哈希类型
# list      列表类型
# set       无序集合
# zset      有序集合

randomkey #随机取出一个key

查看键的值类型

type name
# string
sadd member_list xiaoming xiaohong xiaobai
# (integer) 3
type member_list
# set
hset user_1 name xiaobai age 17 sex 1
# (integer) 3
type user_1
# hash
lpush brothers zhangfei guangyu liubei xiaohei
# (integer) 4
type brothers
# list

zadd achievements 61 xiaoming 62 xiaohong 83 xiaobai  78 xiaohei 87 xiaohui 99 xiaolong
# (integer) 6
type achievements
# zset

删除键以及键对应的值

del key1 key2 ...

查看键的有效期

ttl key

# 结果结果是秒作为单位的整数
# -1 表示永不过期
# -2 表示当前数据已经过期,查看一个不存在的数据的有效期就是-2

设置key的有效期

给已有的数据重新设置有效期,redis中所有的数据都可以通过expire来设置它的有效期。有效期到了,数据就被删除。

expire key seconds

清空所有key

慎用,一旦执行,则redis所有数据库0~15的全部key都会被清除

flushall

key重命名

rename  oldkey newkey

把name重命名为username

set name xioaming
rename name username
get username

select切换数据库

redis的配置文件中,默认有0~15之间的16个数据库,默认操作的就是0号数据库
select <数据库ID>

操作效果:

# 默认处于0号库
127.0.0.1:6379> select 1
OK
# 这是在1号库
127.0.0.1:6379[1]> set name xiaoming
OK
127.0.0.1:6379[1]> select 2
OK
# 这是在2号库
127.0.0.1:6379[2]> set name xiaohei
OK


# 获取所有配置项
reids 127.0.0.1:6379> config get *
# 获取单个配置项
redis 127.0.0.1:6379> config get loglevel
# 编辑配置
redis 127.0.0.1:6379> config set loglevel "notice"

auth认证

在redis中,如果配置了requirepass登录密码,则进入redis-cli的操作数据之前,必须要进行登录认证。
注意:在redis6.0以后,redis新增了用户名和密码登录,可以选择使用,也可以选择不适用,默认关闭的。
      在redis6.0以前,redis只可以在配置文件中,可以选择开启密码认证,也可以关闭密码认证,默认关闭的。
      
redis-cli
127.0.0.1:6379> auth <密码>
OK  # 认证通过

3.6 hash

类似python的字典,但是成员只能是string,专门用于结构化的数据信息。

结构:

键key:{
   	域field:值value
}

设置指定键的属性/域

设置指定键的单个属性,如果key不存在,则表示创建一个key对应的哈希数据,如果key存在,而field不存在,则表示当前哈希数据新增一个成员,如果field存在,则表示修改哈希对应的对应成员的值。

hset key field value
# redis5.0版本以后,hset可以一次性设置多个哈希的成员数据
hset key field1 value1 field2 value2 field3 value3 ...

设置键 user_1的属性namexiaoming

127.0.0.1:6379> hset user_1 name xiaoming   # user_1没有会自动创建
(integer) 1
127.0.0.1:6379> hset user_1 name xiaohei    # user_1中重复的属性会被修改
(integer) 0
127.0.0.1:6379> hset user_1 age 16          # user_1中重复的属性会被新增
(integer) 1
127.0.0.1:6379> hset user:1 name xiaohui    # user:1会在redis界面操作中以:作为目录分隔符
(integer) 1
127.0.0.1:6379> hset user:1 age 15
(integer) 1
127.0.0.1:6379> hset user:2 name xiaohong age 16  # 一次性添加或修改多个属性

设置指定键的多个属性[hmset已经慢慢淘汰了,hset就可以实现多个属性]

hmset key field1 value1 field2 value2 ...

设置键user_1的属性namexiaohong、属性age17,属性sex为1

hmset user:3 name xiaohong age 17 sex 1

获取指定键的域/属性的值

获取指定键所有的域/属性

hkeys key

获取键user的所有域/属性

127.0.0.1:6379> hkeys user:2
1) "name"
2) "age"
127.0.0.1:6379> hkeys user:3
1) "name"
2) "age"
3) "sex"

获取指定键的单个域/属性的值

hget key field

获取键user:3属性name的值

127.0.0.1:6379> hget user:3 name
"xiaohong"

获取指定键的多个域/属性的值

hmget key field1 field2 ...

获取键user:2属性nameage的值

127.0.0.1:6379> hmget user:2 name age
1) "xiaohong"
2) "16"

获取指定键的所有值

hvals key

获取指定键的所有域值对

127.0.0.1:6379> hvals user:3
1) "xiaohong"
2) "17"
3) "1"

删除指定键的域/属性

hdel key field1 field2 ...

删除键user:3的属性sex/age/name,当键中的hash数据没有任何属性,则当前键会被redis删除

hdel user:3 sex age name

判断指定属性/域是否存在于当前键对应的hash中

hexists   key  field

判断user:2中是否存在age属性

127.0.0.1:6379> hexists user:3 age
(integer) 0
127.0.0.1:6379> hexists user:2 age
(integer) 1
127.0.0.1:6379> 

属性值自增自减

hincrby key field number

给user:2的age属性在原值基础上+/-10,然后在age现有值的基础上-2

# 按指定数值自增
127.0.0.1:6379> hincrby user:2 age 10
(integer) 77
127.0.0.1:6379> hincrby user:2 age 10
(integer) 87

# 按指定数值自减
127.0.0.1:6379> hincrby user:2 age -10
(integer) 77
127.0.0.1:6379> hincrby user:2 age -10

获取哈希的所有成员域值对

hgetall key

3.7 list

类似python的lis列表数据类型,但是redis中的list的子成员类型为string。

添加子成员

# 在左侧(前,上)添加一条或多条成员数据
lpush key value1 value2 ...

# 在右侧(后,下)添加一条或多条成员数据
rpush key value1 value2 ...

# 在指定元素的左边(前)/右边(后)插入一个或多个数据
linsert key before 指定成员 value1 value2 ....
linsert key after 指定成员 value1 value2 ....

从键为brother的列表左侧添加一个或多个数据liubei、guanyu、zhangfei

lpush brother liubei
# [liubei]
lpush brother guanyu zhangfei xiaoming
# [xiaoming,zhangfei,guanyu,liubei]

从键为brother的列表右侧添加一个或多个数据,xiaohong,xiaobai,xiaohui

rpush brother xiaohong
# [xiaoming,zhangfei,guanyu,liubei,xiaohong]
rpush brother xiaobai xiaohui
# [xiaoming,zhangfei,guanyu,liubei,xiaohong,xiaobai,xiaohui]

从key=brother,key=xiaohong的列表位置左侧添加一个数据,xiaoA,xiaoB

linsert brother before xiaohong xiaoA
# [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaobai,xiaohui]
linsert brother before xiaohong xiaoB
# [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaoB,xiaohong,xiaobai,xiaohui]

从key=brother,key=xiaohong的列表位置右侧添加一个数据,xiaoC,xiaoD

linsert brother after xiaohong xiaoC
# [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaoC,xiaobai,xiaohui]
linsert brother after xiaohong xiaoD
# [xiaoming,zhangfei,guanyu,liubei,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]

注意:当列表如果存在多个成员值一致的情况下,默认只识别第一个。

127.0.0.1:6379> linsert brother before xiaoA xiaohong
# [xiaoming,zhangfei,guanyu,liubei,xiaohong,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]
127.0.0.1:6379> linsert brother before xiaohong xiaoE
# [xiaoming,zhangfei,guanyu,liubei,xiaoE,xiaohong,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]
127.0.0.1:6379> linsert brother after xiaohong xiaoF
# [xiaoming,zhangfei,guanyu,liubei,xiaoE,xiaohong,xiaoF,xiaoA,xiaohong,xiaoD,xiaoC,xiaobai,xiaohui]

设置指定索引位置成员的值

lset key index value
# 注意:
# redis的列表也有索引,从左往右,从0开始,逐一递增,第1个元素下标为0
# 索引可以是负数,表示尾部开始计数,如`-1`表示最后1个元素

修改键为brother的列表中下标为4的元素值为xiaohongmao

lset brother 4 xiaohonghong

删除指定成员

lrem key count value

# 注意:
# count表示删除的数量,value表示要删除的成员。该命令默认表示将列表从左侧前count个value的元素移除
# count==0,表示删除列表所有值为value的成员
# count >0,表示删除列表左侧开始的前count个value成员
# count <0,表示删除列表右侧开始的前count个value成员

获取列表成员

根据指定的索引获取成员的值

lindex key index

获取brother下标为2以及-2的成员

lindex brother 2
lindex brother -2

移除并获取列表的第一个成员或最后一个成员

lpop key  # 第一个成员出列
rpop key  # 最后一个成员出列

获取并移除brother中的第一个成员

lpop brother
# 开发中往往使用rpush和lpop实现队列的数据结构->实现入列和出列

获取列表的切片

闭区间[包括stop]

lrange key start stop

操作:

# 获取btother的全部成员
lrange brother 0 -1
# 获取brother的前2个成员
lrange brother 0 1

获取列表的长度

llen key

获取brother列表的成员个数

llen brother

3.8 set

类似python里面的set无序集合, 成员是字符串string,重点就是去重和无序。

添加元素

key不存在,则表示新建集合,如果存在则表示给对应集合新增成员。

sadd key member1 member2 ...

向键authors的集合中添加元素zhangsanlisiwangwu

sadd authors zhangsan sili wangwu

获取集合的所有的成员

smembers key

获取键authors的集合中所有元素

smembers authors

获取集合的长度

scard keys 

获取s2集合的长度

sadd s2 a c d e

127.0.0.1:6379> scard s2
(integer) 4

随机获取一个或多个元素

spop key [count=1]

# 注意:
# count为可选参数,不填则默认一个。被提取成员会从集合中被删除掉

随机获取s2集合的成员

sadd s2 a c d e

127.0.0.1:6379> spop s2 
"d"
127.0.0.1:6379> spop s2 
"c"

删除指定元素

srem key value

删除键authors的集合中元素wangwu

srem authors wangwu

交集、差集和并集

sinter  key1 key2 key3 ....    # 交集,比较多个集合中共同存在的成员
sdiff   key1 key2 key3 ....    # 差集,比较多个集合中不同的成员
sunion  key1 key2 key3 ....    # 并集,合并所有集合的成员,并去重
sadd user:1 1 2 3 4     # user:1 = {1,2,3,4}
sadd user:2 1 3 4 5     # user:2 = {1,3,4,5}
sadd user:3 1 3 5 6     # user:3 = {1,3,5,6}
sadd user:4 2 3 4       # user:4 = {2,3,4}

# 交集
127.0.0.1:6379> sinter user:1 user:2
1) "1"
2) "3"
3) "4"
127.0.0.1:6379> sinter user:1 user:3
1) "1"
2) "3"
127.0.0.1:6379> sinter user:1 user:4
1) "2"
2) "3"
3) "4"

127.0.0.1:6379> sinter user:2 user:4
1) "3"
2) "4"

# 并集
127.0.0.1:6379> sunion user:1 user:2 user:4
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

# 差集
127.0.0.1:6379> sdiff user:2 user:3
1) "4"  # 此时可以给user:3推荐4

127.0.0.1:6379> sdiff user:3 user:2
1) "6"  # 此时可以给user:2推荐6

127.0.0.1:6379> sdiff user:1 user:3
1) "2"
2) "4"

3.9 zset

有序集合,去重并且根据score权重值来进行排序的。score从小到大排列。

添加成员

key如果不存在,则表示新建有序集合。

zadd key score1 member1 score2 member2 score3 member3 ....

设置榜单achievements,设置成绩和用户名作为achievements的成员

127.0.0.1:6379> zadd achievements 61 xiaoming 62 xiaohong 83 xiaobai  78 xiaohei 87 xiaohui 99 xiaolan
(integer) 6
127.0.0.1:6379> zadd achievements 85 xiaohuang 
(integer) 1
127.0.0.1:6379> zadd achievements 54 xiaoqing

给指定成员增加权重值

zincrby key score member

给achievements中xiaobai增加10分

127.0.0.1:6379> ZINCRBY achievements 10 xiaobai
"93

获取集合长度

zcard key

获取users的长度

zcard achievements

获取指定成员的权重值

zscore key member

获取users中xiaoming的成绩

127.0.0.1:6379> zscore achievements xiaobai
"93"
127.0.0.1:6379> zscore achievements xiaohong
"62"
127.0.0.1:6379> zscore achievements xiaoming
"61"

获取指定成员在集合中的排名

排名从0开始计算

zrank key member      # score从小到大的排名
zrevrank key member   # score从大到小的排名

获取achievements中xiaohei的分数排名,从大到小

127.0.0.1:6379> zrevrank achievements xiaohei
(integer) 4

获取score在指定区间的所有成员数量

zcount key min max

获取achievements从0~60分之间的人数[闭区间]

127.0.0.1:6379> zadd achievements 60 xiaolv
(integer) 1
127.0.0.1:6379> zcount achievements 0 60
(integer) 2
127.0.0.1:6379> zcount achievements 54 60
(integer) 2

获取score在指定区间的所有成员

zrangebyscore key min max     # 按score进行从低往高排序获取指定score区间
zrevrangebyscore key min max  # 按score进行从高往低排序获取指定score区间
zrange key start stop         # 按scoer进行从低往高排序获取指定索引区间
zrevrange key start stop      # 按scoer进行从高往低排序获取指定索引区间

获取users中60-70之间的数据

127.0.0.1:6379> zrangebyscore achievements 60 90
1) "xiaolv"
2) "xiaoming"
3) "xiaohong"
4) "xiaohei"
5) "xiaohuang"
6) "xiaohui"
127.0.0.1:6379> zrangebyscore achievements 60 80
1) "xiaolv"
2) "xiaoming"
3) "xiaohong"
4) "xiaohei"
# 获取achievements中分数最低的3个数据
127.0.0.1:6379> zrange achievements 0 2
1) "xiaoqing"
2) "xiaolv"
3) "xiaoming"

# 获取achievements中分数最高的3个数据
127.0.0.1:6379> zrevrange achievements 0 2
1) "xiaolan"
2) "xiaobai"
3) "xiaohui"

删除成员

zrem key member1 member2 member3 ....

从achievements中删除xiaoming的数据

zrem achievements xiaoming

删除指定数量的成员

# 删除指定数量的成员,从最低score开始删除
zpopmin key [count]
# 删除指定数量的成员,从最高score开始删除
zpopmax key [count]

例子:

# 从achievements中提取并删除成绩最低的2个数据
127.0.0.1:6379> zpopmin achievements 2
1) "xiaoqing"
2) "54"
3) "xiaolv"
4) "60" 


# 从achievements中提取并删除成绩最高的2个数据
127.0.0.1:6379> zpopmax achievements 2
1) "xiaolan"
2) "99"
3) "xiaobai"
4) "93"

3.10 各种数据类型在开发中的常用业务场景

针对各种数据类型它们的特性,使用场景如下:
字符串string: 用于保存一些项目中的普通数据,只要键值对的都可以保存,例如,保存 session/jwt,定时记录状态,倒计时、验证码、防灌水答案
哈希hash:用于保存项目中的一些对象结构/字典数据,但是不能保存多维的字典,例如,商城的购物车,文章信息,json结构数据
列表list:用于保存项目中的列表数据,但是也不能保存多维的列表,例如,消息队列,秒杀系统,排队,浏览历史
无序集合set: 用于保存项目中的一些不能重复的数据,可以用于过滤,例如,候选人名单, 作者名单,
有序集合zset:用于保存项目中一些不能重复,但是需要进行排序的数据, 例如:分数排行榜, 海选人排行榜,热搜排行,

开发中,redis常用的业务场景:

数据缓存、
分布式数据共享、
计数器、
限流、
位统计(用户打卡、签到)、
购物车、
消息队列、
抽奖奖品池、
排行榜单(搜索排名)、
用户关系记录[收藏、点赞、关注、好友、拉黑]、

开发中,针对redis的使用,python中一般常用的redis模块有:pyredis(同步),aioredis(异步)。

pip install py-redis
pip install aioredis

3.11 python操作redis

这2个模块提供给开发者的使用方式都是一致的。都是以redis命令作为函数名,命令后面的参数作为函数的参数。只有一个特殊:del,del在python属于关键字,所以改成delete即可。

基本使用

from redis import Redis, StrictRedis

conn = Redis(host="127.0.0.1",port=6379,password="",decode_responses=True) #decode_responses=True 设置取出的数据是字符,不是字节

if __name__ == '__main__':
    # 连接redis的写法有2种:
    # url="redis://:密码@IP:端口/数据库编号"
    redis = Redis.from_url(url="redis://:@127.0.0.1:6379/0")
    # redis = Redis(host="127.0.0.1", port=6379, password="", db=0)

    # # 字符串
    # # set name xiaoming
    # redis.set("name", "xiaoming")

    # # setex sms_13312345678 30 500021
    # mobile = 13312345678
    # redis.setex(f"sms_{mobile}", 30, "500021")
    #
    # # get name
    # ret = redis.get("name")
    # # redis中最基本的数据类型是字符串,但是这种字符串是bytes,所以对于python而言,读取出来的字符串数据还要decode才能使用
    # print(ret, ret.decode())

    # # 提取数据,键如果不存在,则返回结果为None
    # code_bytes = redis.get(f"sms_{mobile}")
    # print(code_bytes)
    # if code_bytes: # 判断只有获取到数据才需要decode解码
    #     print(code_bytes.decode())

    # 设置字典,单个成员
    # hset user name xiaoming
    # redis.hset("user", "name", "xiaoming")


    # # 设置字典,多个成员
    # # hset user name xiaohong age 12 sex 1
    # data = {
    #     "name": "xiaohong",
    #     "age": 12,
    #     "sex": 1
    # }
    # redis.hset("user", mapping=data)

    # # 获取字典所有成员,字典的所有成员都是键值对,而键值对也是bytes类型,所以需要推导式进行转换
    # ret = redis.hgetall("user")
    # print(ret)  # {b'name': b'xiaohong', b'age': b'12', b'sex': b'1'}
    # data = {key.decode(): value.decode() for (key, value) in ret.items()}
    # print(data)

    # # 获取当前仓库的所有的key
    ret = redis.keys("*")
    print(ret)

    # 删除key
    if len(ret) > 0:
        redis.delete(ret[0])
        
        
        
        
###### t_redis_pool.py
#redis连接池
import redis
#pool必须是单例的
POOL = redis.ConnectionPool(host="127.0.0.1", port=6379, password="",decode_responses=True, max_connections=100)  # 造一个池子,最多能放100个连接

#######t_redis_conn.py
import redis
#包内的py文件,如果想右键运行,导包的时候不能带点
from t_redis_pool import POOL  # pycharm提示的错
r = redis.Redis(connection_pool=POOL)  # 只要执行这一句话,就是从池中拿出一个连接
r.execute_command('select 1') #选择数据库
ret=r.get('name')
print(ret)

 

#1、set(name, value, ex=None, px=None, nx=False, xx=False)
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
    ex,过期时间(秒)
    px,过期时间(毫秒)
    nx,如果设置为True,则只有name不存在时,当前set操作才执行
    xx,如果设置为True,则只有name存在时,岗前set操作才执行


#2、setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)


#3、setex(name, value, time)
设置值
参数:
    time,过期时间(数字秒 或 timedelta对象)


#4、psetex(name, time_ms, value)
设置值
参数:
    time_ms,过期时间(数字毫秒 或 timedelta对象)


#5、mset(*args, **kwargs)
批量设置值
如:
    mset(k1='v1', k2='v2')
    或
    mset({'k1': 'v1', 'k2': 'v2'})


#6、get(name)
获取值


#7、mget(keys, *args)
批量获取
如:
    mget('k1', 'k2')
    或
    r.mget(['k1', 'k2'])


#8、getset(name, value)
设置新值并获取原来的值


#9、getrange(key, start, end)
获取子序列(根据字节获取,非字符)
参数:
    name,Redis 的 name
    start,起始位置(字节)
    end,结束位置(字节)
    如: "林海峰" ,0-2表示 ""


#10、setrange(name, offset, value)
修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
参数:
    offset,字符串的索引,字节(一个汉字三个字节)
    value,要设置的值

    client.set('name','林海峰')
    client.setrange('name',3,'大海')
    print(client.get('name').decode('utf-8')) #林大海


#11、strlen(name)
返回name对应值的字节长度(一个汉字3个字节)


#12、incr(self, name, amount=1)
自增 name="1" 对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
    name,Redis的name
    amount,自增数(必须是整数)
    注:同incrby


#13、incrbyfloat(self, name, amount=1.0)
自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
    name,Redis的name
    amount,自增数(浮点型)


#14、decr(self, name, amount=1)
自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
参数:
    name,Redis的name
    amount,自减数(整数)


#15、append(key, value)
在redis name对应的值后面追加内容
参数:
    key, redis的name
    value, 要追加的字符串
Redis命令之String
#1、hset(name, key, value)
name对应的hash中设置一个键值对(不存在,则创建;否则,修改)

参数:
    name,redis的name
    key,name对应的hash中的key
    value,name对应的hash中的value

注:
    hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)


#2、hmset(name, mapping)
在name对应的hash中批量设置键值对

参数:
    name,redis的name
    mapping,字典,如:{'k1':'v1', 'k2': 'v2'}

如:
    r.hmset('xx', {'k1':'v1', 'k2': 'v2'})


#3、hget(name,key)
在name对应的hash中获取根据key获取value


#4、hmget(name, keys, *args)
在name对应的hash中获取多个key的值

参数:
    name,reids对应的name
    keys,要获取key集合,如:['k1', 'k2', 'k3']
    *args,要获取的key,如:k1,k2,k3

如:
    r.mget('xx', ['k1', 'k2'])
    或
    print r.hmget('xx', 'k1', 'k2')


#5、hgetall(name)
获取name对应hash的所有键值


#6、hlen(name)
获取name对应的hash中键值对的个数


#7、hkeys(name)
获取name对应的hash中所有的key的值


#8、hvals(name)
获取name对应的hash中所有的value的值


#9、hexists(name, key)
# 检查name对应的hash是否存在当前传入的key


#10、hdel(name,*keys)
将name对应的hash中指定key的键值对删除


#11、hincrby(name, key, amount=1)
自增name对应的hash中的指定key的值,不存在则创建key=amount

参数:
    name,redis中的name
    key, hash对应的key
    amount,自增数(整数)


#12、hincrbyfloat(name, key, amount=1.0)
自增name对应的hash中的指定key的值,不存在则创建key=amount

参数:
    name,redis中的name
    key, hash对应的key
    amount,自增数(浮点数)

自增name对应的hash中的指定key的值,不存在则创建key=amount


#13、hscan(name, cursor=0, match=None, count=None)
增量式迭代获取,对于数据大的数据非常有用,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时,表示数据已经通过分片获取完毕


#14、hscan_iter(name, match=None, count=None)
利用yield封装hscan创建生成器,实现分批去redis中获取数据

参数:
    match,匹配指定key,默认None 表示所有的key
    count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数

如:
    for item in r.hscan_iter('xx'):
        print item


#15、补充scan(match=None, count=None)
一点一点查出当前库下的所有的keys,详细请看如下文档
http://redisdoc.com/key/scan.html#scan
Redis命令之Hash
#1、lpush(name,values)
在name对应的list中添加元素,每个新的元素都添加到列表的最左边

如:
    r.lpush('oo', 11,22,33)
    保存顺序为: 33,22,11

扩展:
    rpush(name, values) 表示从右向左操作


#2、lpushx(name,value)
在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边

更多:
    rpushx(name, value) 表示从右向左操作


#3、llen(name)
name对应的list元素的个数


#4、linsert(name, where, refvalue, value))
在name对应的列表的某一个值前或后插入一个新值

参数:
    name,redis的name
    where,BEFORE或AFTER
    refvalue,标杆值,即:在它前后插入数据
    value,要插入的数据


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

参数:
    name,redis的name
    index,list的索引位置
    value,要设置的值


#6、r.lrem(name, value, num)
在name对应的list中删除指定的值

参数:
    name,redis的name
    value,要删除的值
    num,  num=0,删除列表中所有的指定值;
           num=2,从前到后,删除2个;
           num=-2,从后向前,删除2个


#7、lpop(name)
在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素

更多:
    rpop(name) 表示从右向左操作


#8、lindex(name, index)
在name对应的列表中根据索引获取列表元素


#9、lrange(name, start, end)
在name对应的列表分片获取数据

参数:
    name,redis的name
    start,索引的起始位置
    end,索引结束位置


#10、ltrim(name, start, end)
在name对应的列表中移除没有在start-end索引之间的值

参数:
    name,redis的name
    start,索引的起始位置
    end,索引结束位置


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

参数:
    src,要取数据的列表的name
    dst,要添加数据的列表的name


#12、blpop(keys, timeout)
keys=["k1","k2"],按照从左到右去pop对应列表的元素

参数:
    keys,redis的name的集合
    timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞

举例:
    client.flushdb()
    client.lpush('list1',11,22,33) #33,22,11
    client.lpush('list2','a','b','c') #c b a

    print(client.blpop(["list1","list2"])) #先从左侧取干净list1,再从左侧取干净list2,...,阻塞
    print(client.blpop(["list1","list2"]))
    print(client.blpop(["list1","list2"]))
    print(client.blpop(["list1","list2"]))
    print(client.blpop(["list1","list2"]))
    print(client.blpop(["list1","list2"]))
    print(client.blpop(["list1","list2"],timeout=3)) #阻塞3秒,返回None

更多:
    r.brpop(keys, timeout),从右向左获取数据


#13、brpoplpush(src, dst, timeout=0)
从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧

参数:
    src,取出并要移除元素的列表对应的name
    dst,要插入元素的列表对应的name
    timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞

#14、自定义增量迭代
由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
    1、获取name对应的所有列表
    2、循环列表
但是,如果列表非常大,那么就有可能在第一步时就将程序的内存撑爆,所有有必要自定义一个增量迭代的功能:

def list_iter(name):
    """
    自定义redis列表增量迭代
    :param name: redis中的name,即:迭代name对应的列表
    :return: yield 返回 列表元素
    """
    list_count = r.llen(name)
    for index in range(list_count):
        yield r.lindex(name, index)


# 使用
for item in list_iter('list1'):
    print(item)
Redis命令之List
Set操作,Set集合就是不允许重复的列表

#1、sadd(name,values)
name对应的集合中添加元素


#2、scard(name)
获取name对应的集合中元素个数


#3、sdiff(keys, *args)
在第一个name对应的集合中且不在其他name对应的集合的元素集合


#4、sdiffstore(dest, keys, *args)
获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中


#5、sinter(keys, *args)
获取多一个name对应集合的并集


#6、sinterstore(dest, keys, *args)
获取多一个name对应集合的并集,再讲其加入到dest对应的集合中


#7、sismember(name, value)
检查value是否是name对应的集合的成员


#8、smembers(name)
获取name对应的集合的所有成员


#9、smove(src, dst, value)
将某个成员从一个集合中移动到另外一个集合


#10、spop(name)
从集合的右侧(尾部)移除一个成员,并将其返回


#11、srandmember(name, numbers)
从name对应的集合中随机获取 numbers 个元素


#12、srem(name, values)
在name对应的集合中删除某些值


#13、sunion(keys, *args)
获取多一个name对应的集合的并集


#14、sunionstore(dest,keys, *args)
获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中


#15、sscan(name, cursor=0, match=None, count=None)
#16、sscan_iter(name, match=None, count=None)
同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大
Redis命令之Set
#1、zadd(name, *args, **kwargs)
在name对应的有序集合中添加元素

如:
     zadd('score', 'alex', 50, 'wxx', 60,'yxx', 70)
     或
     zadd('score', alex=50, wxx=60, yxx=70)


#2、zcard(name)
获取name对应的有序集合元素的数量


#3、zcount(name, min, max)
获取name对应的有序集合中分数在 [min,max] 之间的个数


#4、zincrby(name, value, amount)
自增name对应的有序集合的 name 对应的分数


#5、r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
按照索引范围获取name对应的有序集合的元素

参数:
    name,redis的name
    start,有序集合索引起始位置(非负数)
    end,有序集合索引结束位置(非负数)
    desc,排序规则,默认按照分数从小到大排序
    withscores,是否获取元素的分数,默认只获取元素的值
    score_cast_func,对分数进行数据转换的函数
    例如:
        client.zrange('score', 0, 2, desc=True, withscores=True, score_cast_func=int)
        结果:[(b'yxx', 70), (b'wxx', 60), (b'alex', 50)]

更多:
    从大到小排序
    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)


#6、zrank(name, value)
获取某个值在 name对应的有序集合中的排行(从 0 开始)

更多:
    zrevrank(name, value),从大到小排序


#7、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)


#8、zrem(name, values)
删除name对应的有序集合中值是values的成员

如:zrem('zz', ['s1', 's2'])


#9、zremrangebyrank(name, min, max)
根据排行范围删除


#10、zremrangebyscore(name, min, max)
根据分数范围删除


#11、zremrangebylex(name, min, max)
根据值返回删除


#12、zscore(name, value)
获取name对应有序集合中 value 对应的分数


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

例如:
client.flushdb()
client.zadd('score1', 'alex', 50, 'wxx', 60,'yxx', 70)
client.zadd('score2', 'alex', 60, 'wxx', 60,)

#先求名字的交集,再对同一名字对应的值进行SUM聚合操作
client.zinterstore('score_sum',keys=['score1','score2'],aggregate="SUM")
print(client.zscore('score_sum','alex')) #110.0
print(client.zscore('score_sum','wxx')) #120.0
print(client.zscore('score_sum','yxx')) #None


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


#15、zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
#16、zscan_iter(name, match=None, count=None,score_cast_func=float)
同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作
Redis命令之Sort Set
#1、delete(*names)
根据name删除redis中的任意数据类型


#2、exists(name)
检测redis的name是否存在


#3、keys(pattern='*')
根据模型获取redis的name

更多:
    KEYS * 匹配数据库中所有 key 。
    KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
    KEYS h*llo 匹配 hllo 和 heeeeello 等。
    KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo


#4、expire(name ,time)
为某个redis的某个name设置超时时间


#5、rename(src, dst)
对redis的name重命名为


#6、move(name, db))
将redis的某个值移动到指定的db下


#7、randomkey()
随机获取一个redis的name(不删除)


#8、type(name)
获取name对应值的类型


#9、scan(cursor=0, match=None, count=None)
#10、scan_iter(match=None, count=None)
同字符串操作,用于增量迭代获取key
其他常用操作

发布订阅者模式

redis的发布和订阅者模式就像是广播发消息是一样的

发布订阅的特性用来做一个简单的实时聊天系统再适合不过了,当然这样的东西开发中很少涉及到。再比如在分布式架构中,常常会遇到读写分离的场景,在写入的过程中,就可以使用redis发布订阅,使得写入值及时发布到各个读的程序中,就保证数据的完整一致性。再比如,在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们拉。

import redis
conn = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True)
conn.publish("gaoxin333", "18")
redis发布者
import redis
conn = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True)
# 第一步 生成一个订阅者对象
pubsub = conn.pubsub()
# 第二步 订阅一个消息 实际上就是监听这个键
pubsub.subscribe("gaoxin333")
pubsub.parse_response()
# 第三步 死循环一直等待监听结果
while True:
    print("working~~~")
    msg = pubsub.parse_response()
    print(msg)
redis订阅者

# monitor.py
import redis

class RedisHelper:

    def __init__(self):
        self.__conn = redis.Redis(host='127.0.0.1',port=6379)
        self.chan_pub = 'fm97.8' #发布信息的频道名
        self.chan_sub = 'fm97.8' #订阅信息的频道名

    def public(self, msg):
        self.__conn.publish(self.chan_pub, msg) #向发布频道发布消息
        return True

    def subscribe(self):
        pub = self.__conn.pubsub() #拿到pub对象
        pub.subscribe(self.chan_sub) #向订阅频道请求消息
        pub.parse_response() #解析响应的信息
        return pub

#发布者们

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper
import time

obj = RedisHelper()

while True:
    obj.public('hello1')
    time.sleep(5)

#订阅者们

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper

obj = RedisHelper()
redis_sub = obj.subscribe()

while True:
    msg = redis_sub.parse_response()
    print(msg)
fm97.8

管道

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

#1、默认情况下是执行一个操作就向服务端提交一次
#2、可以将一系列操作放入一个管道内,然后一次性提交给服务端,这样做有效地减少开销
#3、transaction=True代表多个操作构成一个事务(原子性操作)

import redis

pool=redis.ConnectionPool(host='127.0.0.1',port=6379,max_connections=100)
client=redis.Redis(connection_pool=pool)

pipe=client.pipeline(transaction=True)

pipe.set('name','alex')
pipe.set('role','sb')

pipe.execute()
管道

 

#1 key-value的存储方式,value有很多数据类型:5大:string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型
#2 内存数据库
#3 与Memcached比较:
    -1 Memcached只支持一种数据类型字符串
    -2 Memcached不支持持久化(不支持存到硬盘上,只要一断电,数据就没了)

# 4 使用Redis有哪些好处?
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
# 5 单线程,单进程,不存在并发访问的问题(新版本已经不是了)
    -单线程为什么这么快
        -数据在内存(最重要的)
        -io多路复用技术
        -因为没有进程,线程间的切换
# 6 redis适合的场景
      1 排行榜
    2 网站访问量,文章访问量
    3 缓存数据库(用的最多,就是做缓存)
    4 发布订阅
    5 去重
    6 分布式(blpop)

# 7 安装
    -Redis-x64-3.2.100.msi  安装包
    -redis-desktop-manager-0.9.3.817.exe 等同于navicate


# 8 启动
    -服务端启动:redis-server 配置文件.conf
    -客户端redis-cli  :客户端连接服务端(redis-cli -h 127.0.0.1 -p 6379)

# 9 应用
    -频率限制类 (继承SimpleRateThrottle,scop,重写getcachekey方法:方法返回什么,就以什么作为key限制,setting中配置)
    -手机号验证码登录,手机号和验证码
    -注册接口
    -5大数据类型:str:接口缓存,list:分布式,hash:缓存,set:去重,zset:排行榜

# 注意事项
    -以后想取出hash类型内所有的数据,不建议用hgetall,建议用hscan_iter

# 制作服务windows下
1.cmd中:
    C:\Users\DELL>d:
    D:\>cd redis
    D:\redis>redis-server --service-install redis.windows-service.conf --loglevel verbose
    D:\redis>mkdir logs
2.打开“运行”,在运行窗口中,输入命令“services.msc”,然后点击“确定”即可打开服务。
3.找到redis服务启动就好了
4.常用的redis服务命令。
    卸载服务:redis-server --service-uninstall
    开启服务:redis-server --service-start
    停止服务:redis-server --service-stop


#####字符串操作
####1 set的用法
# conn.set('height',180) #基本使用

# conn.set('height','190',nx=True)
# conn.set('height','190',xx=True)
# conn.set('height1','190',xx=True)
'''
     ex,过期时间(秒)
     px,过期时间(毫秒)
     nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
     xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''

### 2
# setnx(name, value)
#
# 设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
# setex(name, value, time)
# # 设置值
# # 参数:
#     # time,过期时间(数字秒 或 timedelta对象)
# psetex(name, time_ms, value)
# # 设置值
# # 参数:
#     # time_ms,过期时间(数字毫秒 或 timedelta对象


# mset
# conn.mset({'name1':'11','name3':'dasfd'})

# ret=conn.mget(['name1','name','name3'])
# print(ret)

# ret=conn.getset('name1', '999')
# print(ret)

# ret=conn.getrange('name1',0,0) # 前闭后闭区间
# print(ret)

# conn.setrange('name1',1,88888)

# ret=conn.getbit('name1',9)
# print(ret)

#incr :统计网站访问量,页面访问量,接口访问量
# conn.incr('name1')  # 只要一执行,数字加1
# conn.incr('name1')  # 只要一执行,数字加1
# conn.incr('name1')  # 只要一执行,数字加1
# conn.incr('name1')  # 只要一执行,数字加1

#decr
# conn.incr('name1',-2)
# conn.decr('name1',3)

# conn.append('name1','oo')
# conn.incr('name1')

##重点:
#set :很多参数
#get
#mset
#mget
#incr
#decr
#append



########################################################################
########################################################################
# hash操作
# conn.hset('hash1','name','lqz')
# conn.hset('hash1','name2','lqz')
# conn.hset('hash1','name','lqz444')  # key不可以重复,

# ret=conn.hget('hash1','name')  #只能取一个
# print(ret)


# conn.hmset('hash2',{'key1':'value1','key2':'value2'})
# ret=conn.hmget('hash1','name','name2')
# ret=conn.hmget('hash1',['name','name2'])
# print(ret)

# ret=conn.hgetall('hash1')  # 尽量少用
# print(ret)

# ret=conn.hlen('hash1')
# ret=conn.hkeys('hash1')
# ret=conn.hexists('hash1','name1')
# ret=conn.hdel('hash1','name')

# conn.hset('hash1','name',12)
# ret=conn.hincrby('hash1','name')
#
# print(ret)


# 以后想取出hash类型内所有的数据,不建议用hgetall,建议用hscan_iter
# 一次性先取一部分回来(假设有1w条,先取回100条,把这100条做成了生成器)
# ret=conn.hscan_iter('hash1')
# print(ret)
# for i in ret:
#     print(i)

# 区分hgetall和hscan_iter


########################################################################
########################################################################
### 列表操作
# ret=conn.lpush('list1',1,2,3,4,5)
# ret=conn.rpush('list1',999)
# ret=conn.lpushx('list2',1)

# ret=conn.lpushx('list1',888)  # 必须有这个key才能放
# ret=conn.rpushx('list1',666)  # 我们猜,返回总长度
# ret=conn.llen('list1')

# ret=conn.linsert('list1','before','3','77777777')
# ret=conn.linsert('list1','after','3','66666666')



# ret=conn.lset('list1',3,'22222')  #从0开始计数
# ret=conn.lset('list1',0,'11111')

# ret=conn.lrem('list1',2,'5')  # 从前往后删除两个5
# ret=conn.lrem('list1',-1,'5') # 从后往前删除1个5
# ret=conn.lrem('list1',0,'5')   # 删除所有5

# ret=conn.lpop('list1')
# ret=conn.rpop('list1')

# ret=conn.lindex('list1',0)

# ret=conn.lrange('list1',0,2)  # 前闭后闭

# ret=conn.ltrim('list1',1,2)

# 重点block,阻塞,可以写一个超时时间
# ret=conn.blpop('list1',timeout=10)
# print(ret)


# 自定制分批取列表的数据
# 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)



########################################################################
########################################################################
# 其他操作
# conn.delete('list1')
# ret=conn.delete('hash1')

# ret=conn.exists('hash2')
# ret=conn.keys('cache*')  #查询以cache开头的所有key

# ret=conn.expire('hash2',2)

# ret=conn.type('name3')
# ret=conn.type('test')
# ret=conn.type('test')
print(ret)
########################################################################
########################################################################



# 管道
# redis支持事务
# 管道。实现事务
# import redis
# pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
# 
# conn = redis.Redis(connection_pool=pool)
# 
# pipe = conn.pipeline(transaction=True)
# # pipe.multi()
# pipe.set('name', 'alex')
# 
# pipe.set('role', 'sb')
# 
# pipe.execute()  # 这句话,才真正的去执行


########################################################################
########################################################################

# Django中使用redis

# 方式一(通用方式)
# 方式二:django-redis
    -pip install django-redis
    -setting中配置
        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",
                          "DECODE_RESPONSES":True
                    }
                }
            }
       -使用两种方式
        1 使用cache
        from django.core.cache import cache
        cache.set('name',user)
        2 直接使用conn对象
        from django_redis import get_redis_connection
        conn = get_redis_connection('default')
        print(conn.hgetall('xxx'))

########################################################################
########################################################################
# 接口缓存
# 首页轮播图数据缓存到redis中
def list(self, request, *args, **kwargs):
    # response=super().list(request, *args, **kwargs)
    # 把data的数据加缓存
    # 1 先去缓存拿数据
    banner_list=cache.get('banner_list')
    if not banner_list:
        print('走数据库了')
        # 缓存中没有,去数据库拿
        response = super().list(request, *args, **kwargs)
        # 加到缓存
        cache.set('banner_list',response.data,60*60*24)
        return response

    return Response(data=banner_list)
View Code

 

posted @ 2019-03-08 23:04  silencio。  阅读(228)  评论(0编辑  收藏  举报