02-Redis基础

一、Redis数据操作

1. 数据库操作
# 选择数据库,一共有16个库,i 的范围 0 ~ 15,默认为 0 号库
select i
# 查询数据库容量
dbsize
# 清除当前库
flushdb
# 清除所有库
flushall
2. 数据操作
1)Redis-Key
# 查询数据库中所有key
keys *
# 设置key
set key value
# 判断key是否存在,存在返回1,不存在返回0
exists key
# 移除当前库中的key到指定的库中,如下面的命令将key移动到库1中
move key 1
# 设置key的过期时间i,单位秒,返回-1表示没有过期时间,-2表示key不存在(可能已经过期)
expire key i
# 设置key的同时设置过期时间
set key value ex i
# 查询key的剩余有效原因
ttl key
# 查看key的类型
type key
2)String(字符串)
# 设置值
set key value
# 获取值
get key
# 给key追加字符串,若不存在,则新增一个
append key append_value
# 获取字符串长度
strlen key

######################################################################
#------------步长操作------------
# key自增/自减1
incr/decr key
# 设置增量i,即在 key的值 + i,当 i < 0时即为减量
incrby key i
# 设置减量i, 即key_value - i,当 
decrby key i

######################################################################
#---------字符串范围--------------
# 截取字符串[begin, end],0为第一个字符,-1表示最后一个字符
# 当end的值大于字符串的长度时,截取到末尾结束
# getrange key 0 -1 等价于 get key
getrange key begin end

#替换指定位置开始的字符串
#get key abcdef
#setrange key 1 xx  axxdef
setrange key index value

######################################################################
# setex(set with expire) 设置过期时间
# setnx(set if not exist)	不存在就设置(在分布式锁中会常常使用)
# 设置过期时间,等价于前面说的:set key value ex i
setex key i value
# 若key存在,则创建失败
setnx key value

######################################################################
mset		# 同时设置多个值【k1 v1 k2 v2......】
mget		# 同时获取多个值【mget k1 k2...】
msetnx		# 原子性操作,多个(key,value)中,若有一个已经存在,则该操作会失败,即使其它key不存在

#对象
set user:1 {name:zhangshan,age;3}	# 设置一个user:1对象,值为json字符串来保存对象

# key的巧用:object:{id}:{filed}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 20
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "20"


getset		# 先get后set
127.0.0.1:6379> getset db redis		# 不存在,返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb	# 如果存在,返回原来的值,并设置新值
"redis"
127.0.0.1:6379> get db
"mongodb"


value除了是字符串,还可以是数字:

  • 计数器
  • 统计数量
3)List(列表)

redis中,可以把List当栈、队列、阻塞队列等使用

所有的List命令以L开头

######################################################################
127.0.0.1:6379> lpush list one		# 将一个或多个值放到列表头部(左边)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1		# 获取指定区间的值(从0开始)
1) "three"
2) "two"
127.0.0.1:6379> rpush list right
(integer) 4
127.0.0.1:6379> lrange list 0 -1	# 将一个或多个值插入到列表尾部(右边)
1) "three"
2) "two"
3) "one"
4) "right"

######################################################################
lpop
rpop

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list 
"three"
127.0.0.1:6379> lrange list 0 -1	# 移除列表第一个(头部、左边)值
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> rpop list			# 移除错后一个(尾部、右边)值
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

#移除key中的cnt个element元素
# cnt > 0	从头到尾删除cnt个element元素
# cnt < 0	从尾到头删除|cnt|个element元素
# cnt = =	删除全部值为element元素
lrem key cnt element	

######################################################################
lindex		# 根据下标获取值
	
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> lindex list 0
"two"

######################################################################
llen

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> llen list		# 返回列表长度
(integer) 2

# 截取[begin,end]范围的值,并将其赋值给key
ltrim key begin end

# 移除列表最后一个元素,并放到新列表中
rpoplpush	# 6.2.0被弃用
# 可以使用lmove source destination right left来代替使用

127.0.0.1:6379> lrange list 0 -1
1) "-1"
2) "0"
3) "hello2"
4) "hello1"
5) "hello"
127.0.0.1:6379> rpoplpush list mylist	# 移除列表最后一个元素,并放到新列表中
"hello"	
127.0.0.1:6379> lrange list 0 -1	# 原列表中无被移除的元素
1) "-1"
2) "0"
3) "hello2"
4) "hello1"
127.0.0.1:6379> lrange mylist 0 -1	# 新列表中存在新值
1) "hello"

######################################################################
lset key index value	# 更新指定下标的值,若不存在指定下标,这报错

# element插入到指定的pivot的前/后面
linsert key before/after pivot element
4)Set(集合)

无序无重复集合

# 往Set集合中添加成员
sadd key member[...member]

# 查看指定key的成员
smembers key
# 等价于只有一个key的sinter交集操作
sinter key

# 判断集合key中是否存在成员member
sismember key member
# 判断集合key中的多个成员member是否存在
smismember key member [...member]

# 查询集合成员个数
scard key

# 移除key中指定的成员mem
srem key mem

# 随机选择cnt个成员,默认一个
srandmember key 【cnt】

# 随机删除成员
spop key

# 将指定的成员mem移动到另外的SET集合key2中
smove key1 key2 mem


# 数学集合
127.0.0.1:6379> sadd key1 a b c
(integer) 3
127.0.0.1:6379> sadd key2 c d e
(integer) 3
127.0.0.1:6379> sdiff key1 key2		# 差集(key1 - key2)
1) "b"
2) "a"
127.0.0.1:6379> sinter key1 key2	# 交集
1) "c"
127.0.0.1:6379> sunion key1 key2	# 并集
1) "b"
2) "a"
3) "c"
4) "d"
5) "e"


5)Hash(哈希)

即Map集合,<key, map>

本质与String没区别,唯一的差异是vlaue从一个String变成了 key value 的map对象

Hash更适合存储对象信息,key就是对象名,field就是对象属性,value就是属性对应的值。

###################################################################################
# 设置一个或多个hash,其中key是mykey,value是一个map对象<field, value>
hset mykey field value [...field value]
# 获取key中指定的字段值
hget key field
# 获取key中指定的多个字段值
hmget key field [...field]
# 获取key中所有字段
hgetall key
# 删除key中指定字段field
hdel key field [...field]

127.0.0.1:6379> hset mykey f1 v1 f2 czm f3 v3 f4 ob		# 设置hash
(integer) 4
127.0.0.1:6379> hget mykey f2		# 获取hash中指定field的value
"czm"
127.0.0.1:6379> hmget mykey f2 f4	# 获取hash中指定的多个field的value
1) "czm"
2) "ob"
127.0.0.1:6379> hgetall mykey		# 获取指定hash的所有field和value
1) "f1"
2) "v1"
3) "f2"
4) "czm"
5) "f3"
6) "v3"
7) "f4"
8) "ob"
127.0.0.1:6379> hdel mykey f3		# 删除一个指定field
(integer) 1
127.0.0.1:6379> hgetall mykey
1) "f1"
2) "v1"
3) "f2"
4) "czm"
5) "f4"
6) "ob"
127.0.0.1:6379> hdel mykey f2 f4	# 删除多个指定field
(integer) 2
127.0.0.1:6379> hgetall mykey
1) "f1"
2) "v1"


###################################################################################
# 获取hash长度
hlen key
# 获取hash中指定field的长度
hstrlen key field
# 判断hash中的指定字段是否存在
hexists key field

# 只获取所有的字段
hkeys key
#只获取所有的字段值
hvals key

###################################################################################
# 为key中的字段值加上增量increment,increment < 0时表示减量
hincrby key field increment
# 为key中的字段值减上减量incr,incr > 0 时表示增量

# 当key中存在指定的key时,不操作,不存在则新增
hsetnx key field value
6)ZSet/SortedSet(有序集合)

在Set的基础上新增了一个score,并根据器进行排序,默认升序

###################################################################################
127.0.0.1:6379> zadd salary 2500 xh		# 添加单个成员
(integer) 1
127.0.0.1:6379> zadd salary 2000 zs 500 ks		#添加对各成员
(integer) 2
127.0.0.1:6379> zrange salary 0 -1		# 查询所有成员
1) "ks"
2) "zs"
3) "xh"
127.0.0.1:6379> zrangebyscore salary -inf +inf	# 默认就是升序排序
1) "ks"
2) "zs"
3) "xh"
127.0.0.1:6379> zrevrange salary 0 -1		# zrevrange 从大到小排序
1) "xh"
2) "zs"
3) "ks"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores	# 查询所有成员,并带着score
1) "ks"
2) "500"
3) "zs"
4) "2000"
5) "xh"
6) "2500"

###################################################################################
# 移除集合中的成员
zrem key member
# 获取集合中的个数
zcard key
# 获取集合中指定范围[min, max]的成员个数
zcount key min max

二、Redis持久化

三、Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。如微信、微博、各种关注系统!

redis客户端可以订阅任意数量的频道。

发布订阅消息图:

第一个:消息发送者

第二个:频道

第三个:消息订阅者

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fp1KhW2F-1648989377753)(D:\Install\Typora\typora-user-images\image-20210611112300495.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQTMdZLT-1648989377754)(D:\Install\Typora\typora-user-images\image-20210611112432368.png)]

命令

# 订阅给定的一个或多个频道的信息
subscribe channel [...channel]
# 将消息message发送到指定的频道channel
publish channel message
# 退订指定频道,若未指定,则退订所有频道
unsubscribe [channel ...]


# 订阅一个或多个符合给定模式的频道
psubscribe pattern [...pattern]
# 退订所有给定模式的频道
punsubscribe pattern


# 查看发布订阅系统状态
pubsub <subcommand>
# 列出当前活跃频道
pubsub channels

测试

订阅端:

127.0.0.1:6379> subscribe omaster		# 订阅消息一个频道 omaster
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "omaster"
3) (integer) 1
# 等待读取频道推送的消息
1) "message"		# 类型;消息
2) "omaster"		# 消息来源:哪个频道
3) "hello omaster"		# 消息的具体内容

1) "message"
2) "omaster"
3) "hello_redis"

发送端:

127.0.0.1:6379> publish omaster "hello omaster"		# 发布者发布消息到频道
(integer) 1
127.0.0.1:6379> publish omaster hello_redis		# 发布者发布消息到频道
(integer) 1

原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bj4DAY79-1648989377755)(D:\Install\Typora\typora-user-images\image-20210611134222969.png)]

使用场景

1、实时消息系统

2、实时聊天系统(频道当作聊天室,将信息发送给所有人)

3、订阅、关注等

稍复杂的系统使用消息队列中间件

四、Redis主从复制/哨兵模式

1. 主从复制(一主二从)

主从复制,读写分离,主机写,从机读,80%的情况下都是读操作,两从机,减缓主服务器压力。

[外链