万字长文入门 Redis 命令、事务、锁、订阅、性能测试

作者:痴者工良

Redis 基本数据类型

Redis 中,常用的数据类型有以下几种:

  • String:字符串类型, 二进制安全字符串
  • Hash:哈希表;
  • List 列表:链表结构,按照插入顺序排序的字符串元素的集合;
  • Set:集合,元素具有唯一性,未排序的字符串元素集合;
  • Sorted Set:有序集合;
  • Bit arrays:二进制数据;

Redis 的 Key

Redis 的键是二进制安全的,意味着无论 Key 中的内容是什么,在 Redis 都可以正常使用,例如 Key 中可以包含空格、 \r\n¥$ 等特殊字符,因为它们都会被转为二进制存储,它们不再是具有意义的字符串,而是一堆 01 组成的内容。你可以使用普通字符串做 Key ,也可以使用一张图片做 Key,只要 Key 小于 512MB 即可

Redis Key 命名

Redis Key 的命名一般都是小写,命名主要以便于阅读为主,同时考虑缩短 Key,减少内存占用,例如 user:1000:followers 便于阅读,而 u1000flw 很短可以减少内存占用,但可读性不高。

Key 可以如果要表达有层次结构,则可以使用 : 组合 ,如要表达 租户(id1)=>技术部(id5)=>后端(id1)=>工号006,每层对象在数据库中都有一个表存储,且每个对象都有一个 Id,则可以使用 tenant:01:department:05:group:01:user:006 做 Key,在某些工具下,Key 会被以树的形式显示,便于查找,其显示如下图所示:

万字长文入门 Redis 命令、事务、锁、订阅、性能测试

如果 Key 某一个部分是多词字段,则可以使用 .- 连接,如 comment:1234:reply.tocomment:1234:reply-to,表示 Id 为 1234 的评论被回复的信息列表。

由于 Redis 的 Key 是很宽松的,因此命名规则不必限定,可以根据团队内部讨论觉得使用何种分隔符分割层次、使用长命名还是缩短命名习惯等。

一般更加建议是使用 {对象名称}:{对象标识/id}:{对象属性} 表示,如 用户1的消息列表表示为 user:1:messages,如果是租户隔离,还可以表示用户相关信息为 tenant:1:user:1:messagestenant:1:user:1.messages

设置 Key 过期时间

Redis 的过期时间设置有四种形式:

  • EXPIRE 秒——设置指定的过期时间(秒),表示的是时间间隔。
  • PEXPIRE 毫秒——设置指定的过期时间,以毫秒为单位,表示的是时间间隔。
  • EXPIREAT 时间戳-秒——设置指定的 Key 过期的 Unix 时间,单位为秒,表示的是时间/时刻。
  • PEXPIREAT 时间戳-毫秒——设置指定的 Key 到期的 Unix 时间,以毫秒为单位,表示的是时间/时刻。

如设置一个 Key 在 5s 后过期:

127.0.0.1:6379> expire value 5
(integer) 1

设置 Key 在 2021年11月26日22时过期:

2021-11-26 22:00:00
127.0.0.1:6379> expireat value 1637935200
(integer) 1

有些类型本身或类型的元素的命令参数可以设置过期时间,如 string 类型,可以不使用 expire 等相关命令。

使用 ttl 命令,可以查看一个 Key 的过期时间,返回剩余存活秒数。

2021-11-26 22:00:00
127.0.0.1:6379> expireat value 1637935200
(integer) 1
127.0.0.1:6379> ttl value
(integer) 4760

Redis 7.0 后 expire 命令有以下参数可用:

  • NX ——只有当密钥没有过期时才设置过期
  • XX — 仅当键具有现有的过期时才设置过期
  • GT 仅当新的有效期大于当前有效期时才设置有效期
  • LT ——只有当新的有效期小于当前有效期时才设置有效期

笔者在编写这篇文章时,使用的 redis:latest 镜像,其版本是 6.2.6,因此暂未使用这些参数,你可以使用 info 命令查看 Redis 信息:

127.0.0.1:6379> info
Server
redis_version:6.2.6
... ...

Redis 使用 expires 字典存储了所有 Key 的过期时间。

判断键是否存在

exist 命令可以判断一个 Key 是否存在,如果存在则返回 1,否则返回 0 。

redis> exist key1
(integer) 1
redis> exist nosuchkey
(integer) 0

搜索 Key

keys 命令可以搜索符合条件的 Key,如 keys * 则返回全部 key。

搜索以 t 开头的所有 key
keys t*
搜索包含 test 的 key
keys *test*

使用 dbsize 命令可以知道 Key 的数量:

127.0.0.1:6379> dbsize
(integer) 5

scan 则可以指定搜索多少条符合条件的 key:

返回一条以 t 开头的 key
scan 0 match t* count 1

可参考: https://redis.io/commands/scan

can 命令格式入下

scan cursor [MATCH pattern] [COUNT count] [TYPE type]

cursor 是一个游标值,scan 每次结果的是在上一次迭代,表示开始位置,如果不注意,可能会导致查找结果与需要的不一样。如 Redis 中有三个 user:{id} Key,我想搜索符合条件的这三个值:

127.0.0.1:6379> scan 0 match  "user:*" count 5
1) "10"
2) 1) "user:3"
   2) "user:1"

搜索结果一直很奇怪。

这是因为是当前游标是 1) "10" 在 10;而且scan 只会返回部分数量的 Key,不会返回所有数量。所以如果要使用 scan 命令,我们要注意以下步骤。

笔者的完整 Key 如下:

 1) "test"
 2) "user:1"
 3) "key"
 4) "user:3"
 5) "Sicily"
 6) "test1"
 7) "zset"
 8) "deck"
 9) "h"
10) "year"
11) "user:2"

注意 user:{id} 的位置。

重置游标:

127.0.0.1:6379> scan 0
1) "7"
2)  1) "Sicily"
    2) "user:3"
    3) "deck"
    4) "test"
    5) "user:1"
    6) "year"
    7) "h"
    8) "key"
    9) "test1"
   10) "zset"

注意,此时游标位置在 7,这个是 Redis 分配的, 具有不确定性

搜索:

127.0.0.1:6379> scan 0 match  "user:*" count 100
1) "0"
2) 1) "user:3"
   2) "user:1"
   3) "user:2"

首先,当我们使用 scan 0 时,游标重新在 0 开始,因为没有设置值,因此 Redis 分配到了 7。另外游标的意思并不是下次从 7 开始搜索,而是指当前游标识别了 0-7 中的 Key,你下次搜索的结果将会在 0-7 中搜索!因此笔者给其设置了 count 100,这样游标会一直往下走,直至找到符合数量的 Key 或 Key 已经检索完毕。

要注意, SCAN 命令并不保证每次执行都返回某个给定数量的元素

如下所示,重置游标后,它自动检索到 7,默认最大 10,此时我们的关键字在 0-7中搜索,不加 count 默认只会找到两个 Key,那么我将 count 数量改成 3,那他不就可以找到三个元素了?这里我们直接设置为 5 试试:

127.0.0.1:6379> scan 0
1) "7"
2)  1) "Sicily"
    2) "user:3"
    3) "deck"
    4) "test"
    5) "user:1"
    6) "year"
    7) "h"
    8) "key"
    9) "test1"
   10) "zset"
127.0.0.1:6379> scan 0 match  "user:*" count 5
1) "10"
2) 1) "user:3"
   2) "user:1"

结果事与愿违,游标只走到 10 ,并且结果只有两个,而不是 3 个。

如果你把 count 设置大一点,可能便可以搜索到需要的 3 个 Key 了:

127.0.0.1:6379> scan 0 match  "user:*" count 11
1) "0"
2) 1) "user:3"
   2) "user:1"
   3) "user:2"

注意, scan cursorscan cursor match ... 命令不一样,前者是重置游标检索位置,将范围内的 Key 当搜索结果搜集起来;而 scan cursor match ... 指从哪个位置开始搜索。

在 Redis 的很多类型中,如列表、集合,都支持搜索,它们的命令格式中有个 pattern 字段,其支持 glob 风格的通配符区配格式,也使用这种风格区配 Key。其规则或说明如下:

符号 说明 ? 表示一个任意字符,如 tes? test

符合结果; * 区配任意数量的字符,如 *

表示所有; t*

表示以 t 开头; [] 区配方括号间的任一个字符,可以使用 -

表示一个范围,与正则表达式类似;如 t[a-d]*

,以 t 开头,第二个字符是 a,b,cd

中的一个; \x x 表示一个字符;用于将前面三个符号转义,使其失去特殊意义,如 \? \*

另外 Redis 的命令关键字不区分大小写。

判断键类型

type 命令可以获取一个 Key 的 Value 的类型:

127.0.0.1:6379> set value 123455
OK
127.0.0.1:6379> type value
string
127.0.0.1:6379> rpush value2 abc
(integer) 1
127.0.0.1:6379> type value2
list

删除键

del 命令可以删除一个 Key:

127.0.0.1:6379> del value2
(integer) 1
127.0.0.1:6379> del value2 value
(integer) 1

返回删除的 Key 数量;如果 Key 不存在,del 命令不会报错,只会返回受影响的数量;

前面提到, Redis 支持模糊搜索 Key,可以很容易查找符合条件的 Key,但是 Redis 不支持模糊删除 Key。

RESP 协议

RESP 协议用于编写 Redis 客户端,它定义了 Redis 请求和响应的格式内容,当我们使用 redis-cli 工具连接 Redis 并执行命令时,返回的数据格式跟 RESP 有关系,这里简单说一下,Redis 响应的格式主要有:

  • 对于 简单字符串,回复的第一个字节是”+”
  • 对于 错误,回复的第一个字节是”-“
  • 对于 整数,回复的第一个字节是”:”
  • 对于 批量字符串,回复的第一个字节是”$”
  • 对于 数组,回复的第一个字节是” *

在 redis-cli 或别的工具中,第一个符号可能不会显示,例如 "+ok",在工具中只给用户显示 "ok" ;响应包含 ok 则说明命令执行成功;nil 表示 Null Bulk String,也 nil 可以表达为 ok 的反义,即失败,但不代表发生错误,不同的编程语言客户端应将 nil 表示为其语言的相关空类型,例如 go 语言返回 nil,C# 返回 null,C 语言返回 NULL 等,在 redis-cli 中显示为 (nil)。

以上符号只是对响应内容进行初步解析,具体含义要根据发送的命令以及编程语言特点做二次处理。如 del bar 命令,删除一个 Key,响应内容:

127.0.0.1:6379> del bar
(integer) 0

redis-cli 工具中看到的不是原始的消息内容,如果直接接收 TCP 消息,其内容应该是 :0,客户端可以通过前面的 : 符号了解到后面的是数字,于是吧 0 截取处理,转为数字;但是这个数字结合 del 命令才有意义,这部分则要看编程语言的特点做处理。

这里不必深入了解 RESP 协议,只需要大概了解使用 redis-cli 等工具执行 Redis 命令时,响应结果代表什么意义即可。

字符串类型

Redis 的字符串类型也是二进制安全的,二进制安全并不是指线程安全,而是指无论你存储什么内容都可以,Redis string 最大可以存储 512 MB,可以往里面塞一些小姐姐视频、图片、网页、文件等都没问题。

面试题:Redis 相比 memcached 有哪些优势

  • memcached 只支持简单的字符串类型,而 Redis 支持多种类型;
  • Redis 速度更加快;
  • Redis 的数据可以持久化;

下面介绍一些 string 常用的指令。

使用 setget 对单个 Key 进行写或读,使用 msetmget 对多个 Key 批量写或读。

> set mykey somevalue
OK
> get mykey
"somevalue"
> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"

默认情况下,当 Key 已存在时, setmset 会替换其值;当 Key 不存在时, setmset 会创建新的 Key,而 Redis 提供了 NX、XX 两个参数,可以改变这种替换或新创建行为。如果一个 Key 存在并具有过期时间等属性时,如果使用 set 等命令替换 Key 时,过期时间等属性会自动消除。

NX:当 Key 不存在时才生效。

127.0.0.1:6379> set key1 666 nx
"OK"
127.0.0.1:6379> set key1 666 nx
(nil)

Key 不存在时,set 命令正常;当 Key 不存在时,set 命令报 nil。
如果响应的信息以 - 开头,则表示一个错误。

XX:当 Key 存在时才生效。

127.0.0.1:6379> set key1 666 xx
OK
127.0.0.1:6379> del key1    # 删除键
(integer) 1
127.0.0.1:6379> set key1 666 xx
(nil)

Key 存在时,set 命令正常;当 Key 不存在时,set 命令报 nil。

完整的 set 命令定义如下:

set key value [EX seconds|PX milliseconds|EXAT timestamp|PXAT milliseconds-timestamp|KEEPTTL] [NX|XX] [GET]

可参考 https://redis.io/commands/set

下面介绍一下这些参数:

  • EX 秒——设置指定的过期时间(秒),表示的是时间间隔。
  • PX 毫秒——设置指定的过期时间,以毫秒为单位,表示的是时间间隔。
  • EXAT 时间戳-秒——设置指定的 Key 过期的 Unix 时间,单位为秒,表示的是时间/时刻。
  • PXAT 时间戳-毫秒——设置指定的 Key 到期的 Unix 时间,以毫秒为单位,表示的是时间/时刻。
  • NX ——当 Key 不存在时才设置值。
  • XX ——当 Key 存在时才设置值。
  • KEEPTTL ——保留设置前指定键的生存时间,即替换 Key 时,保留 Key 的过期时间设置。
  • GET ——如果 Key 已存在,使用 set 命令会替换 Key,加上 get 可以取得替换之前的值;如果 Key 不存在,则返回 nil。

EX、PX、EXAT、PXAT 都是设置时间的,其中 EX、PX 都是表示时间间隔,即自设置起还有多久此 Key 过期;而 EXAT 、PXAT 都是表示过期时刻,即什么时候过期,EXAT 是 10 位时间戳,如设置 2021-11-25 22:33:48 此 Key 过期,则时间戳为 1637850828;而 PXAT 是十三位的时间戳。

KEEPTTL 参数可以让 Key 继承旧 Key 的过期时间,如果一个 Key 设置了 100 秒后过期,那么当 set 命令替换 Key 前还有 90 秒过期,当替换后,新的 Key 会在 90 秒后过期。

示例:

127.0.0.1:6379> set key1 666 EX 10  get
"666"
127.0.0.1:6379> set key1 666 KEEPTTL get
"666"

string 类型也可以使用原子操作,相当于 C# 的 Interlocked.Increment、Java 的 AtomicInteger、Go 的 atomic,在 Redis 中称为 atomic increment(原子增量)。

原子操作主要有 INCR、INCRBY、DECR、DECRBY 四种,前两种是增量,后两种是减量。

127.0.0.1:6379> set value 100
OK
127.0.0.1:6379> incr value      # 自加 1
(integer) 101
127.0.0.1:6379> incrby value 5  # 指定加量
(integer) 106

INCR 可以用作统计访问量、注册账号递增的 ID 等。Redis 的原子操作对所有客户端生效,避免此客户端操作时,值被另一个客户端操作覆盖。

原子增量是双精确度类型,你可以使用 incrby value 5.0 甚至 incrby value 5E+4 加值。

string 类型具有以下列出的命令,有部分命令可能已经失效或在将来的版本中去除,本文只列举部分常用的命令,读者可参考官网文档说明。

Redis 命令有上百个,即使是常用的 Linux 命令也没有这么多,没必要强硬记住这些命令。

  • APPEND :追加字符串;
  • DECR:原子操作,减 1;
  • DECRBY:原子操作,减指定值;
  • GET:获取字符串值;
  • GETDEL:获取字符串值后删除 Key;
  • GETEX:获取字符串并设置过期时间,单位秒;
  • GETRANGE:获取字符串中的一部分字符;
  • GETSET:设置字符串值并返回旧字符串值;
  • INCR:原子操作,加 1;
  • INCRBY:原子操作,加指定值;
  • INCRBYFLOAT:原子操作,浮点数加指定值;
  • MGET:获取多个字符串 key;
  • MSET:同时设置多个字符串 ;
  • MSETNX:对多个字符串进行原子级别的设置值,这些 key 同时改变值;
  • PSETEX:获取字符串并设置过期时间,单位毫秒;
  • SET:设置字符串值;
  • SETEX:设置字符串并设置过期时间,单位秒;
  • SETNX:字符串不存在时才设置值;
  • SETRANGE:覆盖字符串的部分值,从偏移量 offset 设定的位置开始替换为新的字符串;
  • STRALGO:STRALGO LCS,不知道是什么东西;
  • STRLEN:获取字符串的字符数量;

位操作

位图不是实际的数据类型,而是在 String 类型上定义的一组面向位的操作,当然,从逻辑上也可以说 Bit 类型,前面提到过字符串是二进制安全的,它们的最大长度为 512 MB,使用二进制存储,因此有,因此它们适合设置为232个不同的位。

Redis 的字符串实现叫 简单动态字符串(Simple dynamic string),简称 SDS,按照存储空间的大小拆分成为了 sdshdr5sdshdr8sdshdr16sdshdr32sdshdr64,其中 5、8、16、32、64 表示位数,例如 32 位,最大可以表示为 4GB。但是 Redis 中 Key 字符串值默认最大为 512MB,因此 sdshdr64 并没有实际使用到,sdshdr32 也是 “残血” 状态。

位操作主要有以下五个命令:

所述SETBIT命令采用作为第一个参数的比特数,和作为第二个参数的值以设置所述位,其为1或0的命令自动放大字符串,如果寻址位是当前字符串长度之外。

1,SETBIT:设置指定位的值;
2,GETBIT:仅返回指定索引处的位值,超出范围的位不会报错,会显示 0;
3,BITOP:在不同的字符串之间执行按位运算,提供的操作是 AND、OR、XOR 和 NOT。
4,BITCOUNT: 统计字符串的二进制位中 1 的个数;
5,BITPOS:返回字符串中设置为 1 或 0 的第一位的位置。

要注意,Redis 使用 C 语言编写,使用 char* 类型存储字符串,而在 C 语言中,char 是一个字节,而其他语言可能是两个字节;字符串存储的数字是字符串,以 ASCII 表示,因此,每位字符使用一个 char 表示,每个 char 8 位程度;但是中文等字符,不能按照此规则,例如 Unicode 使用4字节表示,UTF-8 使用3字节表示,那么中文的 帅 字,使用 UTF8 表示,其二进制为 11100101 10111000 10000101

Redis 的字符串是二进制安全的,当我们使用 C# 或 Go 语言编写时,需将字符串转为二进制数据,此时由编程语言编写的客户端决定了 Redis 中要存储的二进制数据,然后通过 TCP 发送二进制数据到 Redis 中,读者可参考 教你写个简单的 Redis Client 框架

首先,在字符串中,存储 1 这个字符串:

127.0.0.1:6379> set a1 1
OK

在工具中查看 a1 的 16 进制表示,在 ASCII 中使用 31 表示 "1",二进制表示为 0011 0001

万字长文入门 Redis 命令、事务、锁、订阅、性能测试

所以,使用 BITCOUNT 命令时,返回结果是 3:

127.0.0.1:6379> bitcount a1
127.0.0.1:6379> bitcount a1 0 -1
(integer) 3

获取 1,3,7 位的值:

127.0.0.1:6379> getbit a1 0
(integer) 1
127.0.0.1:6379> getbit a1 1
(integer) 1
127.0.0.1:6379> getbit a1 2
(integer) 1
127.0.0.1:6379> getbit a1 7
(integer) 1

BITOP 可以让多个值之间进行位运算,即 与(&)或(|)异或(^)非(~) 四个基本操作,多个字符串值的二进制位数可以不相等。

BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP NOT destkey srckey

示例:

127.0.0.1:6379> set a1 1
OK
127.0.0.1:6379> set a2 2
OK
127.0.0.1:6379> set a2 帅
OK
127.0.0.1:6379> bitop and a1 a2
(integer) 3
127.0.0.1:6379> get a1
"\xe5\xb8\x85"

11100101 10111000 10000101 帅
AND
                  00110001 1(ASCII 31)
00100001 00000000 00000000 !

11100101 10111000 10000101 帅
XOR
                  00110001 1(ASCII 31)
11010100 10111000 10000101 (无对于中文)

BITFIELD 也是一个很有用的命令,可以指定在某些位置填充字符。

BITFIELD 命令格式如下:

BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]

在 Redis 中,整型可以使用 i8、i16 等表示,其中 i8 表示 8 位二进制组成的数字,值在 0-127 之间;而无符号使用 u8、u16 等表示。使用 BITFIELD 命令时,会返回上一次的值。

127.0.0.1:6379> BITFIELD mystring SET i8 #0 100 SET i8 #1 200
1) (integer) 0
2) (integer) 0
127.0.0.1:6379> BITFIELD mystring SET i8 #0 100 SET i8 #1 200
1) (integer) 100
2) (integer) -56

# 后面的数字表示字节偏移量, SET i8 #0 100 表示将第一个字节设置为值为 i8 表示的 100。由于 i8 范围在 0-127,因此 200 使用 u8 表示,发生溢出,结果为 -56。但是不代表有问题,因为存储的时候 i8 和 u8 表示 200 都是 11001000(0xc8),存储二进制时不会区分正负,但是当你设置了 i8,则它在返回旧值的时候,按照给定的数据类型转换,因此 11001000 会显示 -56,但是 正负不影响存入结果

如果值过大,则会发生溢出。如:

...  ...

127.0.0.1:6379> BITFIELD mystring SET i8 #0 100 SET i8 #1 257
1) (integer) 100
2) (integer) 1

BITFIELD 还有个好玩的地方是可以在某一位上使用原子增量,格式示例 incrby i8 0 1

127.0.0.1:6379> BITFIELD mystring SET i8 #0 1 SET i8 #1 2
1) (integer) 1
2) (integer) 2
127.0.0.1:6379> BITFIELD mystring  incrby i8 0 1
1) (integer) 2

incrby 参数后面可以带上溢出控制,避免自增后的数溢出,有 WRAP、SAT、FAIL,默认是 WRAP 模式,溢出了也没问题。

而 WRAP 会从负数到正数范围内取值,如 i8 则为 -127~+128;而 SAT 模式在递增时,如果即将发生溢出,那么他不会执行此操作,将值一直保持为 127。

WRAP
127.0.0.1:6379> BITFIELD mystring SET i8 #0 127
1) (integer) 127
127.0.0.1:6379> BITFIELD mystring  incrby i8 0 1
1) (integer) -128
127.0.0.1:6379> BITFIELD mystring  incrby i8 0 257
1) (integer) -127
SAT
127.0.0.1:6379> BITFIELD mystring SET i8 #0 127
1) (integer) 127
127.0.0.1:6379> BITFIELD mystring overflow sat incrby i8 #0 1
1) (integer) 127
127.0.0.1:6379> BITFIELD mystring overflow sat incrby i8 #0 1
1) (integer) 127

如果溢出控制模式为 FAIL,会对检测到的上溢或下溢执行任何操作。相应的返回值设置为 NULL 以向调用者发出条件信号:

127.0.0.1:6379> BITFIELD mystring overflow fail incrby i8 #0 128
1) (nil)

列表类型

Redis 的 list 类型是 链表,区别与一些语言的 List 类型,例如 C# 的 List 、Go 的切片类型内部使用数组实现。因为 Redis list 是链表,所以 list 类型最平常的操作是头部或尾部添加/移除元素,头部或尾部的操作速度和时间跟元素数量不相关,1百万个元素和1千万个元素的操作速度是相同的。当然 list 的查找速度比数组慢。一个 list 最多可以包含 232- 1 个元素(4294967295)。

list 使用 lpush 和 rpush 命令在头部或尾部插入元素,使用 lpop 和 rpop 命令在头部或尾部移除元素:

127.0.0.1:6379> lpush list a b c d
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> rpush list 1 2 3 4
(integer) 8
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"
7) "3"
8) "4"

lpop 和 rpop 移除元素时,可以指定弹出的元素数量,如果不指定,默认数量是 1:

127.0.0.1:6379> lpop list 2
1) "d"
2) "c"

要注意, lpush list 1 2 3,结果是 3 2 1,而不是 1 2 3,因为每一个元素都会从左边插入,相当于跑过第一,就是你第一。
插入过程:

1
3
2
1

除了 LPOP、RPOP,还有其它弹出头部和尾部的命令。

BLPOP、BRPOP:从多个键的头部或尾部弹出一个元素;

LMPOP(Redis 7.0 后可用):在多个键中弹出多个元素,示例: LMPOP 2 mylist mylist2 right count 3

BLMPOP:阻塞版本的 LMPOP;

lrange 表示从 list 的头部取一定范围的元素,其格式是 lrange {key} start stopstart stop 表示元素下标范围,如取下标为 0-5 的六个元素:

127.0.0.1:6379> lrange list 0 5
1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"

如果要获取全部元素,stop 取值为 -1:

127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"
7) "3"
8) "4"

lset 可以通过指定索引设置元素的值:

127.0.0.1:6379> lrange list 0 -1
 1) "a"
 2) "1"
127.0.0.1:6379> lset list 0 b
OK
127.0.0.1:6379> lrange list 0 -1
 1) "b"
 2) "1"

可以使用 llen 获取 list 的元素数量:

127.0.0.1:6379> llen list
(integer) 8

lindex 可以获取指定索引下标的元素的值:

1) "d"
2) "c"
3) "b"
4) "a"
5) "1"
6) "2"
7) "3"
8) "4"
127.0.0.1:6379> lindex list 0
"d"

lrem 命令可以从 list 的左边或右边开始扫描,移除 N 个值为 value 的元素:

127.0.0.1:6379> lrem list 2 b
(integer) 1

lrem 的命令格式为 lrem {key} [count] {value} ,如果 count 为 0 ,则表示移除全部值 {value} 的元素;如果 count > 0,则从左边开始扫描,移除对应数量的元素;如果 count < 0,则从右边开始扫描,移除 |count| 个对应的元素。

linsert 可以在指定元素值前或后插入一个新的值,其命令格式如下:

linsert  key BEFORE|AFTER pivot element
privot &#x5143;&#x7D20;&#x503C;
127.0.0.1:6379> lpush list 3 2 1 1 2 3 3 2 2 1 1
(integer) 11
127.0.0.1:6379> lrange list 0 -1
 1) "1"
 2) "1"
 3) "2"
 4) "2"
 5) "3"
 6) "3"
 7) "2"
 8) "1"
 9) "1"
10) "2"
11) "3"
127.0.0.1:6379> linsert list before 1 a
(integer) 12
127.0.0.1:6379> lrange list 0 -1
 1) "a"
 2) "1"
 3) "1"
 4) "2"
 5) "2"
 6) "3"
 7) "3"
 8) "2"
 9) "1"
10) "1"
11) "2"
12) "3"

lmove 命令可以从一个 list 中弹出头部或尾部,然后压入另一个 list 中,其格式: LMOVE source destination LEFT|RIGHT LEFT|RIGHT

127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> lrange test 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lmove list test right right
"d"
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> lrange test 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "d"

示例中,由于两个位置参数都是 right,因此只处理 “list” 中的尾部元素,并压入到 “testt” 中。

`
list: a b c d
test: 1 2 3 4

Original: https://www.cnblogs.com/whuanle/p/15708800.html
Author: 痴者工良
Title: 万字长文入门 Redis 命令、事务、锁、订阅、性能测试

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529162/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 初识前后端

    初识前后端 在学习了解前后端的过程中,自己看到了这一篇好的文章,摘下了一些当下用的的内容,供复习参考。 什么是前端开发? 前端开发主要涉及网站和 App,用户能够从 App 屏幕或…

    Linux 2023年6月13日
    0108
  • docker 安装redis

    安装docker https://www.cnblogs.com/ximensama/p/14903105.html 安装redis https://www.cnblogs.com…

    Linux 2023年5月28日
    082
  • Debian中CodeIgniter+nginx+MariaDB+phpMyAdmin配置

    本文不讲述软件安装过程,记述本人在Debia 中配置CodeIgniter 时遇到的问题及解决方法,希望能够为有需要的人提供帮助。 一、Debian版本及所需的软件 Debian …

    Linux 2023年6月13日
    093
  • 蓝桥杯国赛——循环小数

    时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分 【问题描述】已知 S 是一个小于 1 的循环小数,请计算与 S 相等的最简真分数是多少。例如 0 . 3333…

    Linux 2023年6月6日
    063
  • 笔记本 vmware 搭建的k8s 集群出现磁盘io爆满,node无法运行pod

    问题描述: k8s集群只有一个master节点和一个node节点,运行了一些java pod 之后出现磁盘io 爆满,pod无法调度和新建,但是节点的内存和磁盘空间都是充足的。 问…

    Linux 2023年6月14日
    099
  • IDEA链接MySQL报错:服务器返回无效时区

    Server returns invalid timezone. Go to ‘Advanced’ tab and set ‘serverTim…

    Linux 2023年6月14日
    098
  • 全网唯一的、DIY的Prometheus高可用方案,生产未上,测试先行。

    写在开篇 关于prometheus的高可用方案,经过笔者不断的研究、对比、和搜索,发现不管是官方、还是各大搜索引擎搜索出来的方案,都不符合笔者的需求。因此,笔者自己设计了一套pro…

    Linux 2023年6月7日
    075
  • Java动态脚本Groovy,高级啊!

    前言:请各大网友尊重本人原创知识分享,谨记本人博客: 南国以南i 简介: Groovy是用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编…

    Linux 2023年6月14日
    0128
  • 零成本搭建个人博客搭建篇

    为什么要搭建个人博客 尽管已经有很多成型的在线博客平台供大家使用(csdn,博客园,掘金等),但是它们都有一些很明显的弊端,例如账号以及博客内容受到监管,所有权不属于作者本人,对于…

    Linux 2023年6月7日
    054
  • 高等代数(上)丘维声 笔记

    1 线性方程组的解法 1、线性方程组:左端为未知量x的一次齐次式,右端是常数。关键词:系数、常数项、n元线性方程组、解集 2、线性方程组的初等变换:1)把一个方程的倍数加到另一个方…

    Linux 2023年6月8日
    095
  • Redis 全局通用命令整理

    转载请注明出处: 1.查看所有键 该命令会存在线程阻塞问题,keys 命令也可以通过正则匹配获取存在的缓存数据 Redis从2.8版本后,提供了一个新的命令scan,它能有效的解决…

    Linux 2023年5月28日
    079
  • spring boot设置日志打印为控制台输出和文件输出

    日志打印 sources里建 logback-spring.xml ${CONSOLE_LOG_PATTERN} ${CONSOLE_LOG_CHARSET} ${FILE_LOG…

    Linux 2023年6月7日
    0105
  • 5.5 Vim移动光标命令汇总

    Vim 文本编辑器中,最简单的移动光标的方式是使用方向键,但这种方式的效率太低,更高效的方式使用快捷键。 Vim 移动光标常用的快捷键及其功能如下面各表所示,需要注意的是,表中所有…

    Linux 2023年6月7日
    094
  • iostream 未完

    声明控制从标准流读取和写入到标准流的对象。 通常是唯一需要从 C++ 程序执行输入和输出的标头。 #include <iostream></iostream&gt…

    Linux 2023年6月7日
    055
  • Redis的快照持久化-RDB与AOF

    Redis为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边。 数据保存到硬盘的过程就称为&#822…

    Linux 2023年5月28日
    086
  • Windows下配置Redis多实例

    方法一:新建目录创建Redis实例 1.将你的redis安装目录复制一份,命名为Redis6380 2.用命令行CMD工具进入到该目录下 3.执行创建redis6380服务的命令:…

    Linux 2023年5月28日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球