目录
Redis的入门学习(一)
/      

Redis的入门学习(一)

Redis(REmote DIctionary Server) 远程字典服务器

Redis 的单线程IO多路复用模型

Redis 是基于 reactor 模型开了网络事件处理器,这个处理器叫做文件事件处理器,这个文件事件处理器是单线程的,所以Redis才叫做单线程模型;IO多路复用是IO模型的一种,多路指的是多个Socket连接,复用指的是复用一个线程。

文件事件处理器的结构包含4个部分:

  • 多个Socket
  • IO多路复用程序,监听多个Socket
  • 文件事件分派器,分派事件
  • 事件处理器:命令请求处理器、命令回复处理器、连接应答处理器

具体实现步骤:

1、主线程负责接收建立连接的多个Socket放入全局等待队列中,等待读处理队列

2、主线程通过轮询将可读Socket分配给IO线程

3、此时主线程阻塞等待IO线程读取Socket完成

4、主线程执行IO线程读取和解析出来的Redis请求命令

5、主线程阻塞等待IO线程,将指令的执行结果写回Socket

6、主线程会清空全局队列,等待客户端的后续请求。

也就是说具体命令执行还是有main线程所在事件循环单线程处理,只是读写Socket事件由IO线程来处理。

Redis 真的是单线程吗?

  • Redis 4.0 引入多线程处理的异步操作,通过非阻塞命令进行异步化,避免阻塞单线程的事件循环
  • Redis 6.0 在网络模型中实现多线程IO,我们平常说redis是单线程,主要指的是redis的网络IO的读取与数据库操作都是在同一个线程中完成的。在Redis 6.0 中引入多线程IO,也只是用来处理网络数据的读写和协议的解析,而执行命令依旧是单线程。

对于 CPU的命令调用始终是单线程的,因为这里涉及从用户态到系统态的切换

工作原理

redis是一个开源的使用ANSI C语言编写的, 存在内存的。

mysql 基于磁盘的

MOH28K.png

用途:

  • 内存存储和持久化:redis支持异步将内存中 的数据写到硬盘上,同时不影响继续服务欧获取最新n个数据的操作,如: 可以将最新的10条评论的id放在redis的list集合里面,模拟类似于HttpSession这种需要设定过期时间的功能
  • 发布, 订阅消息系统
  • 定时器, 计数器

redis特性:

  • 速度快
  • 键值对的数据结构服务器
  • 丰富的功能
  • 简单稳定
    • 主线程是一个单线程
  • 持久化
  • 主从复制
  • 高可用和分布式转移
    • 24不间断运行
  • 客户端语言多

Redis极大程度地获益于单线程、非阻塞、多路复用的I/O模型。当然某些情况下,Redis也会创建线程或子进程来执行某些任务

Redis基本上就是一个接受并处理来自客户端请求的非阻塞、I/O复用的TCP服务器。虽然Redis服务器很复杂,但我们可以使用各种编程语言通过TCP协议与Redis进行通信。术语协议(protocol)代表网络通信中服务器和客户端之间使用的语言。对于Redis来说,这种通信协议叫做REdis Serializtion Protocol (RESP, redis序列化协议)。

改默认配置文件 redis.conf

requirepass 密码

#数据库的数量,默认使用的数据库是0。可以通过”SELECT 【数据库序号】“命令选择一个数据库,序号从0开始
databases 16

#是否在后台执行,yes:后台运行;no:不是后台运行
daemonize yes

#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,
拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭,设置为no
protected-mode yes

#redis监听的端口号
port 6379

redis连接

  • redis-cli 启动redis命令行
  • redis-cli -h host -p port -a password 启动远程的redis服务
  • auth 12345678

    验证密码是否正确

nianshao@nianshao-PC:~$ redis-cli
127.0.0.1:6379> auth 12345678
OK
127.0.0.1:6379> 
  • set key value 设置指定的key
  • get key 获取指定key的值
  • getrange key start end 返回key中字符串值的子字符

redis的优雅关闭

学会如何优雅地停止redis服务端以保持数据的一致性,是非常重要的。

强烈推荐使用shutdown命令停止redis的服务。原因在于,如果我们关心数据一致性且配置了数据持久化来将内存中的数据保存带磁盘中,那么shutdown命令发出后,除了终结进程外,还会执行一系列的其他操作。

127.0.0.1:6379> shutdown
[root@localhost ~]# 

首先,redis-server会停止相应客户端的连接,然后,如果启用了持久化,则会执行数据持久化操作。之后,如果.pid文件和socket套接字描述符存在的话,则对其清理,并最终退出进程。通过这种策略,redis会尽可能地防止数据丢失。相反,如果粗暴地使用kill命令来终止redis-server进程,那么由于在服务端关闭之前数据可能尚未被持久化而导致数据丢失。

获取服务器信息

命令: info

127.0.0.1:6379> INFO

获取指定信息 Info + 参数

127.0.0.1:6379> INFO memory
# Memory
used_memory:840800
used_memory_human:821.09K
used_memory_rss:3776512
used_memory_rss_human:3.60M
used_memory_peak:841776
used_memory_peak_human:822.05K
used_memory_peak_perc:99.88%

另外一种方式就是在命令行直接使用, 使用这种方式,可以非常方便地将命令的输出通过管道重定向到一个脚本中来进行指标分析或性能监控

redis-cli -a 密码 info 

info命令返回信息的全部段落

段落名称描述
server关于redis服务器的基本信息
clients客户端连接的状态和指标
memory大致的内存消耗指标
persistence数据持久化相关的状态和指标
stats总体统计数据
replication主从复制相关的状态和指标
cpucpu使用情况
clusterredis cluster的状态
keyspace数据库相关的统计数据

redis的五大数据类型

  • redis字符串(String)
  • redis列表(List)
  • redis集合(Set)
  • redis哈希(Hash)
  • redis有序集合Zset(sorted set)

redis字符串

Redis 是一种KV存储结构,他的Key是字符串类型,值也支持字符串,所以字符串是redis最常见的一个类型了。Redis自己本身是通过C语言实现的,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS(Simple Dynamic String) 即简单动态字符串。

原因是 C语言中,字符串是通过字符数组实现的,他会在字符数组的最后一个字符处记录 \0 ,来标记这个字符串结束了,也就意味着字符串中不能含有 \0 这个字符串,否则他就会从前面截断。

为了解决上述问题,那就是在用字符数组表示字符串的同时,在这个字符串中增加一个表示分配给该字符数组的总长度的alloc字段,和一个表示字符串现有长度的len字段。这样在获取长度的时候就不依赖 \0 了,直接返回 len 的值就行了。

设置键值对

set name zhangsan

获取字符串的值

get name

当 get 一个不存在的键时,会返回 (nil)

strlen命令返回字符串的长度


默认16个数据库,类似数组下标从零开始, 初始默认使用零号库

  • select 切换数据库, select 1
  • dbsize 查看当前数据库的key的数量
  • flushdb 清空当前库
  • flushall 清空全部库

获取指定范围的字符串 getrange a 0 4

127.0.0.1:6379> set a xxkasbfa
OK
127.0.0.1:6379> getrange a 0 4
"xxkas"

范围内设值 set key 下标 值。

127.0.0.1:6379> get a
"xxkasbfa"
127.0.0.1:6379> setrange a 0 123
(integer) 8
127.0.0.1:6379> get a
"123asbfa"

扩充字符串 append key 值

如果append 的那个 不存在,那么会自动创建这个key,并值赋给这个key

192.168.44.130:0>get b
nil
192.168.44.130:0>append b 123
"3"
192.168.44.130:0>get b
"123"
192.168.44.130:0>get a
"9999999"
192.168.44.130:0>append a 111
"10"
192.168.44.130:0>get a
"9999999111"

字符串批量操作 more

mset批量设值

192.168.44.130:0>mset c 12 d 13 e 14 f 15
"OK"
192.168.44.130:0>keys  *
 1)  "f"
 2)  "d"
 3)  "a"
 4)  "c"
 5)  "b"
 6)  "e"

mget批量获取值

192.168.44.130:0>mget a b c d e f
 1)  "9999999111"
 2)  "123"
 3)  "12"
 4)  "13"
 5)  "14"
 6)  "15"

msetnx 和上面一样的道理.

msetnx 批量设置,如果key已经存在,不再赋新值,否则不进行任何操作。
但setnx 与这个的不同是:当key不存在时,会先创建,再赋值。

getset 先获取值, 再设值

127.0.0.1:6379> get a
"99"
127.0.0.1:6379> getset a 102
"99"
127.0.0.1:6379> get a
"102"

Redis内部是如何进行编码的

Redis提供了三种不同的编码方式来存储字符串对象,并会根据每个字符串值自动决定所使用的编码方式。

  • int :用于能够使用64位有符号整数表示的字符串
  • embstr : 用于长度小于或等于44字节(在Redis 3.x中曾经是39字节)的字符串;这种类型的编码在内存使用和性能方面更有效率。
  • raw : 用于长度大于44字节的字符串

我们可以使用 object 命令来查看与键相关联的Redis值对象的内部编码方式:

127.0.0.1:6379> mget a b c d e f g h 
1) "9999999111"
2) "123"
3) "12"
4) "13"
5) "14"
6) "15"
7) "a long string whose length is more than 44 bytes"
8) "as"
127.0.0.1:6379> OBJECT encoding b
"int"
127.0.0.1:6379> OBJECT encoding a
"raw"
127.0.0.1:6379> OBJECT encoding h
"embstr"

key管理操作

incr 自增1, decr 自减1

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> incr a
(integer) 2
127.0.0.1:6379> get a
"2"
127.0.0.1:6379> incr a
(integer) 3
127.0.0.1:6379> get a
"3"
127.0.0.1:6379> incr a
(integer) 4
127.0.0.1:6379> get a
"4"
127.0.0.1:6379> decr a
(integer) 3
127.0.0.1:6379> decr a
(integer) 2
127.0.0.1:6379> decr a
(integer) 1
127.0.0.1:6379> decr a
(integer) 0
127.0.0.1:6379> decr a
(integer) -1
127.0.0.1:6379> decr a
(integer) -2
127.0.0.1:6379> get a
"-2"

incrby 指定增加, decrby 指定减少

127.0.0.1:6379> get a
"-2"
127.0.0.1:6379> incrby a 5
(integer) 3
127.0.0.1:6379> get a
"3"
127.0.0.1:6379> decrby a 9
(integer) -6
127.0.0.1:6379> get a
"-6"

setex 设置过期时间

这个ex 是 expire的缩写

ttl 查看存活时间

127.0.0.1:6379> setex b 10 123456
OK
127.0.0.1:6379> ttl b
(integer) 8
127.0.0.1:6379> ttl b
(integer) 6
127.0.0.1:6379> get b
"123456"'
127.0.0.1:6379> ttl b
(integer) -2
127.0.0.1:6379> get b
(nil)

设置指定key过期时间。 expire key 秒

pexpire key 毫秒 设置key的生命周期以毫秒为单位

192.168.44.130:0>expire c 20
"1"
192.168.44.130:0>ttl c
"15"
192.168.44.130:0>ttl c
"13"
192.168.44.130:0>ttl c
"13"
192.168.44.130:0>ttl c
"12"
192.168.44.130:0>get c
"666666666666"
192.168.44.130:0>get c
"666666666666"
192.168.44.130:0>get c
nil

setnx 设置值, 如何key已有值, 则不再设置新值,如果key不存在,则创建并赋值。

如果key已有值 返回0,否则 将值赋给key,并返回 1

127.0.0.1:6379> get a
"123asbfa"
127.0.0.1:6379> get b
"456"
127.0.0.1:6379> setnx a b
(integer) 0
127.0.0.1:6379> get a
"123asbfa"
127.0.0.1:6379> setnx c b
(integer) 1
127.0.0.1:6379> get c
"b"

删除指定的key

删除的key如果存在,返回1,如果删除的key不存在 则返回0

192.168.44.130:0>set b 123
"OK"
192.168.44.130:0>get b
"123"
192.168.44.130:0>del b
"1"
192.168.44.130:0>get b
nil
192.168.44.130:0>del b
"0"

**查看key长度 strlen key **

192.168.44.130:0>get a
"9999999"
192.168.44.130:0>strlen a
"7"

exists key 查看是否存在 指定的 key

如果存在,返回1,否则返回0

192.168.44.130:0>keys *
 1)  "a"
192.168.44.130:0>exists a
"1"
192.168.44.130:0>exists b
"0"

redis列表

Redis中的列表更像是数据结构世界中的双向链表


lpush、rpush和linsert会返回插入后列表的长度。在向列表中插入元素前,无需为一个键初始化一个空列表。如果我们向一个不存在的键中插入元素,Redis将首先创建一个空列表并将其与键关联。同样,我们也不需要为删除为空列表的键,因为Redis会为我们回收这种键。

单值多value

lpush: l 就是left, 从左边插入

rpush: 从右边插入

lrange:

返回存储在 key 的列表里指定范围内的元素。 start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。

偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。

127.0.0.1:6379> lpush list01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> rpush list02 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

在指定元素插入其他元素 可以用 linsert

linsert key 指定元素 before|after pivot 内容
这里的pivot代表 元素中内容,如果list中有个 pivot,则选择最先发现的那个元素。

127.0.0.1:6379> lrange a 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> linsert a before 1 "before 1 insert"
(integer) 6
127.0.0.1:6379> lrange a 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "before 1 insert"
6) "1"

127.0.0.1:6379> linsert a after 1 "after 1 insert"
(integer) 7
127.0.0.1:6379> lrange a 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "before 1 insert"
6) "1"
7) "after 1 insert"

lpop和rpop 移除一个元素

127.0.0.1:6379> lpop a
"5"
127.0.0.1:6379> lpop a
"4"
127.0.0.1:6379> lrange a 0 -1
1) "3"
2) "2"
3) "before 1 insert"
4) "1"
5) "after 1 insert"


127.0.0.1:6379> rpop a
"after 1 insert"
127.0.0.1:6379> lrange a 0 -1
1) "3"
2) "2"
3) "before 1 insert"
4) "1"

lindex 按照下标获得元素(从上到下)

127.0.0.1:6379> lindex a 0
"3"
127.0.0.1:6379> lindex a 3
"1"

llen 查看list元素数量

127.0.0.1:6379> llen a 
(integer) 4

lrem 删除n个指定value值

lrem key count value

127.0.0.1:6379> lrange a 0 -1
 1) "3"
 2) "2"
 3) "before 1 insert"
 4) "1"
 5) "3"
 6) "3"
 7) "3"
 8) "3"
 9) "3"
10) "3"
11) "3"
12) "3"
13) "6"
14) "6"
15) "6"
16) "6"
17) "6"
18) "6"
19) "6"
127.0.0.1:6379> lrem a 6 6
(integer) 6
127.0.0.1:6379> lrange a 0 -1
 1) "3"
 2) "2"
 3) "before 1 insert"
 4) "1"
 5) "3"
 6) "3"
 7) "3"
 8) "3"
 9) "3"
10) "3"
11) "3"
12) "3"
13) "6"
127.0.0.1:6379> 

ltrim key 开始index结束index, 截取指定范围的值后再赋值给key

[3, 7] 闭区间, 两边的值是可取的.

127.0.0.1:6379> lrange list02 0 -1
1) "34"
2) "3"
3) "3"
4) "3"
5) "2"
6) "1"
7) "1"
8) "2"
9) "4"
127.0.0.1:6379> ltrim list02 3 7
OK
127.0.0.1:6379> 
127.0.0.1:6379> lrange list02 0 -1
1) "3"
2) "2"
3) "1"
4) "1"
5) "2"

rpoplpush list02 list1 将list02中最下边的一个元素移出, 添加到list01最左边的位置

将list02最右边的一个元素移出,放到list01的最左边

127.0.0.1:6379> lrange list01 0 -1
1) "2"
2) "1"
127.0.0.1:6379> lrange list02 0 -1 
1) "3"
2) "2"
3) "1"
4) "1"
5) "2"
127.0.0.1:6379> rpoplpush list02 list01
"2"
127.0.0.1:6379> lrange list01 0 -1
1) "2"
2) "2"
3) "1"
127.0.0.1:6379> lrange list02 0 -1 
1) "3"
2) "2"
3) "1"
4) "1"

更多细节

LPOP和RPOP命令有对应的阻塞版本:BLPOP和BRPOP。与非阻塞版本类似,阻塞版本的命令也从列表中的左端或右端弹出元素;但是,当列表为空的时候,阻塞版本会将客户端阻塞。 我们必须在阻塞版本的命令中指定一个以秒为单位的超时时间,表示最长等待几秒。 **当超时时间为0时,表示永久等待。**这个特性在任务调度场景中非常有用;在这种场景下,多个任务执行程序(Redis客户端)会等待任务调度程序分配新的任务。任务执行程序中只需要对Redis的列表使用BLPOP和BRPOP,之后每当有新任务时,调度程序把任务插入到列表中,而任务执行程序之一便会获得该任务。

使用哈希(hash)类型

哈希表示字段和值之间的映射关系,与某些编程语言中的map或字典类型相似。Redis数据集本身就可以看作一个哈希,其中字符串类型的键关联到诸如字符串和列表之类的数据对象。而Redis的数据对象也可以再次使用哈希,其字段和值必须时字符串类型。为了与Redis的键进行区分,我们使用 “ 字段(field) ” 来表示哈希中值对象所关联的键。哈希对于存储对象属性而言是一种完美的数据类型。

操作

格式 hmset key field value, 可以设置多个。

同理 hmget,从一个哈希中获取某个字段对应的值

127.0.0.1:6379[2]> hmset student name zhangsan sex 男
OK
127.0.0.1:6379[2]> hmget student name sex
1) "zhangsan"
2) "\xe7\x94\xb7"

使用hexists命令测试一个哈希中是否存在某个字段

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

127.0.0.1:6379[2]> hexists student sex
(integer) 1
127.0.0.1:6379[2]> hexists student school
(integer) 0

使用hgetall命令获取一个哈希中所有的字段和值

127.0.0.1:6379[2]> hgetall student
1) "name"
2) "zhangsan"
3) "sex"
4) "\xe7\x94\xb7"

提示:不建议对数量巨大的哈希使用HGETALL。

使用hdel命令从哈希中删除字段

127.0.0.1:6379[2]> hdel student sex
(integer) 1
127.0.0.1:6379[2]> hgetall student
1) "name"
2) "zhangsan"
127.0.0.1:6379[2]> 

总的来说hash有点类似 一个 对象,hash中的字段和值,有点像对象中的属性和属性值。

默认情况下,hset和hmset会覆盖现有的字段,hsetnx命令则仅在字段不存在的情况下才会设置字段的值,可用于防止hset的默认覆盖行为。

更多细节

一个哈希最多能够容纳2^32 - 1个字段。如果一个哈希的字段非常多,那么执行hgetall命令时会阻塞Redis服务器。在这种情况下,我们可以使用hscan命令来增量地获取所有字段和值

hscan命令是Redis中scan命令的一种(scan、hscan、sscan、zscan),该命令会增量地迭代遍历元素,从而不会造成服务器阻塞。hscan命令是一种基于指针的迭代器,因此我们需要每次调用命令时指定一个游标(从0开始)。当一次hscan运行结束后,Redis将返回一个元素列表以及一个新的游标,这个游标可以用于下一次迭代。

  • hscan key cursor [match pattern] [count number]
  • 选项match用来匹配满足指定glob表达式的字段。
  • 选项count用来说明在每次迭代中应该返回多少个元素。但是,这个选项仅仅是一种参考,Redis并不保证返回的元素就是count个,count的默认值是10.

假如我们有一个非常大的哈希,其中有数百万甚至更多个字段。

127.0.0.1:6379[2]> hscan student 0 match *s*
1) "0"
2)  1) "school"
    2) "aynu"
    3) "sex"
    4) "nan"
    5) "swim"
    6) "13"
    7) "skin"
    8) "14"
    9) "sars"
   10) "16"
   11) "sd"
   12) "17"
   13) "smo"
  1. 0 这个0是由服务器返回的新游标,我们可以用这个游标进一步迭代。当服务器返回的新游标为0时,意味着整个遍历完成。

Redis在内部使用两种编码来存储哈希对象:

  • ziplist : 对于那些长度小于配置中hash-max-ziplist-entries选项配置的值(默认为512),且所有元素的大小都小于配置中hash-max-ziplist-value选项配置的值(默认为64字节)的哈希,采用此编码。ziplist编码对于较小的哈希而言可以节省占用空间。
  • hashtable : 当ziplist不适用时 使用的默认编码。

使用集合(set)类型

集合类型是由唯一、无需对象组成的集合(collection)。它经常用于测试某个成员是否在集合中、重复项删除和集合运算(求并、交、差集)。Redis的值对象可以是字符串集合。

添加命令

sadd key member [member member]

127.0.0.1:6379[2]> sadd hobbies 1 2 3 4 5 6 7 "play basketball"
(integer) 8

查询所有的元素 smembers

smembers 命令列出集合中的所有元素。但是,与我们使用哈希类型中提到的hgetall类似,在一个大集合中使用smembers命令 可能会阻塞 服务器。

因此 我们应该使用sscan命令。sscan命令与我们在使用哈希类型中介绍的hscan命令用法非常类似。

127.0.0.1:6379[2]> smembers hobbies
1) "7"
2) "6"
3) "4"
4) "play basketball"
5) "5"
6) "2"
7) "1"
8) "3"

返回的第一个数是游标,如果游标是0,代表整个集合遍历完成。

127.0.0.1:6379[2]> sscan hobbies 0 match * count 3
1) "4"
2) 1) "7"
   2) "6"
   3) "4"
   
127.0.0.1:6379[2]> sscan hobbies 4 match * count 4
1) "3"
2) 1) "play basketball"
   2) "5"
   3) "3"
   4) "1"

127.0.0.1:6379[2]> sscan hobbies 0 match *
1) "0"
2) 1) "7"
   2) "6"
   3) "4"
   4) "play basketball"
   5) "5"
   6) "3"
   7) "1"
   8) "2"

测试一个元素是否位于集合中。 sismemeber

127.0.0.1:6379[2]> sismember hobbies gitsilence
(integer) 0
127.0.0.1:6379[2]> sismember hobbies "play basketball"
(integer) 1

从集合中删除元素。 srem

127.0.0.1:6379[2]> srem hobbies 4
(integer) 1
127.0.0.1:6379[2]> sscan hobbies 0 match *
1) "0"
2) 1) "7"
   2) "6"
   3) "play basketball"
   4) "5"
   5) "3"
   6) "1"
   7) "2"

获取集合中的成员数量。scard

127.0.0.1:6379[2]> scard hobbies
(integer) 7

Redis提供了一组集合运算相关的命令,sunion和sunionstore用于计算并集。singter 和 singterstore 用于计算交际,sdiff 和 sdiffstore 用于计算差集。 不带store后缀的命令只返回相应操作的集合,而带store后缀的命令则会将结果存储到一个指定的键中。

例如:

有两个集合,分别为hobbies和like

127.0.0.1:6379[2]> smembers hobbies
1) "7"
2) "6"
3) "play basketball"
4) "5"
5) "2"
6) "1"
7) "3"

127.0.0.1:6379[2]> smembers like
1) "8"
2) "7"
3) "4"
4) "9"
5) "2"
6) "play guitar"
7) "1"
8) "3"
9) "10"

并集,没有后缀store

命令格式 sunion key key .... 返回结果

127.0.0.1:6379[2]> sunion hobbies like
 1) "4"
 2) "5"
 3) "play guitar"
 4) "2"
 5) "3"
 6) "7"
 7) "6"
 8) "8"
 9) "9"
10) "play basketball"
11) "1"
12) "10"

并集,有后缀store

格式:sunionstore destination key key ....

这里意思是将 并集的结果 存储的新的key上。

127.0.0.1:6379[2]> sunionstore newSet hobbies like
(integer) 12
127.0.0.1:6379[2]> smembers newSet
 1) "4"
 2) "5"
 3) "play guitar"
 4) "2"
 5) "3"
 6) "7"
 7) "6"
 8) "8"
 9) "9"
10) "play basketball"
11) "1"
12) "10"

同理交集 sinter 和 sinterstore

127.0.0.1:6379[2]> sinter hobbies like
1) "7"
2) "2"
3) "1"
4) "3"
127.0.0.1:6379[2]> sinterstore newInter hobbies like
(integer) 4
127.0.0.1:6379[2]> smembers newInter
1) "1"
2) "2"
3) "3"
4) "7"
127.0.0.1:6379[2]> 

同理差集 sdiff 和 sdiffstore

127.0.0.1:6379[2]> sdiff hobbies like
1) "6"
2) "5"
3) "play basketball"
127.0.0.1:6379[2]> sdiffstore newDiff hobbies like
(integer) 3
127.0.0.1:6379[2]> smembers newDiff
1) "6"
2) "5"
3) "play basketball"

Redis在内部使用两种编码方式来存储集合对象

  • intset : 对于那些元素都是整数,且元素个数小于配置中 set-max-inset-entries选项设置的值(默认512)的集合,采用此编码。intset编码对于较小的集合而言可以节省占用空间。
  • hashtable :intset 不适用时的默认编码。

使用有序集合(sorted set ) 类型

添加元素的命令。zadd、key、分数值、值

根据分数值进行排序,默认是降序

127.0.0.1:6379[2]> zadd set01 10 "cc" 20 "hall" 30 "hello" 40 "alibaba"
(integer) 4
127.0.0.1:6379[2]> zrevrange set01 0 -1
1) "alibaba"
2) "hello"
3) "hall"
4) "cc"

127.0.0.1:6379[2]> zrevrange set01 0 -1 withscores
1) "alibaba"
2) "40"
3) "hello"
4) "30"
5) "hall"
6) "20"
7) "cc"
8) "10"

获取排名的命令。zrevrange

zrevrange key start end [withscores] 降序

zrange key start end [withscores] 升序

withscores 携带 分数值

❤?zincrby 对元素下分数值增加。相当于提高优先级

127.0.0.1:6379[2]> zincrby set01 30 "hello"
"60"
127.0.0.1:6379[2]> zrevrange set01 0 -1 withscores
1) "hello"
2) "60"
3) "alibaba"
4) "40"
5) "hall"
6) "20"
7) "cc"
8) "10"

获取指定元素 所对应的分数值。zscore

127.0.0.1:6379[2]> zscore set01 "hello"
"60"

获取指定元素的排名。如果成员是有序集 key 的成员,返回成员的排名。 如果成员不是有序集 key 的成员,返回 nil 。zrevrank

127.0.0.1:6379[2]> zrevrange set01 0 -1  # 降序
1) "hello"
2) "alibaba"
3) "hall"
4) "cc"
127.0.0.1:6379[2]> zrange set01 0 -1  # 升序
1) "cc"
2) "hall"
3) "alibaba"
4) "hello"

127.0.0.1:6379[2]> zrevrange set01 0 -1 withscores
1) "hello"
2) "60"
3) "alibaba"
4) "40"
5) "hall"
6) "20"
7) "cc"
8) "10"


127.0.0.1:6379[2]> zrevrank set01 "hello"  # 排在第一个
(integer) 0
127.0.0.1:6379[2]> zrevrank set01 "cc"		# 排在最后一个,下标 为3
(integer) 3
127.0.0.1:6379[2]> zrevrank set01 "hall"  # 排在第三个,下标 为2
(integer) 2

其他命令同set命令

更多细节

Redis在内部使用两种编码方式存储有序集合对象

  • ziplist : 对于那些长度小于配置中 zset-max-ziplist-entries 选项配置的值(默认为128),且所有元素的大小都小于配置中zset-max-ziplist-value 选项配置的值(默认为64字节)的有序集合,采用此编码。ziplist用于节省集合所占用的空间。
  • skiplist : 当ziplist不适用时,使用此编码。

使用HyperLogLog类型

使用Geo类型

键管理

获取Redis中键的个数

127.0.0.1:6379[2]> dbsize
(integer) 8

获取Redis服务器中所有的键

  • 第一种方式
127.0.0.1:6379[2]> keys *
1) "newDiff"
2) "newInter"
3) "set01"
4) "like"
5) "newSet"
6) "student"
7) "hobbies"
8) "alist"

  • 第二种方式
127.0.0.1:6379[2]> scan 0
1) "0"
2) 1) "newSet"
   2) "set01"
   3) "hobbies"
   4) "newDiff"
   5) "newInter"
   6) "student"
   7) "like"
   8) "alist"

删除Redis中的键

127.0.0.1:6379> del a
(integer) 1

判断一个键是否存在

127.0.0.1:6379> exists a
(integer) 0

获取键的数据类型

127.0.0.1:6379[2]> type alist
list

键的重命名

127.0.0.1:6379[2]> rename alist blist
OK
127.0.0.1:6379[2]> keys *
1) "blist"
2) "like"
3) "newSet"
4) "student"
5) "newInter"
6) "newDiff"
7) "set01"
8) "hobbies"

Redis 的发布订阅

Redis 的事务

Redis 支持分布式环境下的事务操作,其事务可以一次执行多个命令,事务中的所有命令都会序列化地顺序执行。事务在执行过程中,不会被其他客户端发送来的命令请求打断。服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令。Redis 的事务操作分为开启事务、命令入队列、执行事务三个阶段。Redis 的事务执行流程如下:

  • 事务开启:客户端执行 Multi 命令开启事务
  • 提交请求:客户端提交命令到事务
  • 任务入队列:Redis将客户端请求放入事务队列中等待执行。
  • 入队列状态反馈:服务器返回 QURUD,表示命令已放入事务队列。
  • 执行命令:客户端通过 Exec 执行事务
  • 事务执行错误:在Redis事务中如果某条命令执行错误,则其他命令会继续执行,不会回拨,不会回滚。可以通过Watch监控事务执行的状态并处理命令执行错误的异常情况。
  • 执行结果反馈:服务器向客户端返回事务执行的结果。

标题:Redis的入门学习(一)
作者:gitsilence
地址:http://blog.lacknb.cn/articles/2020/06/27/1593252828222.html