本文翻译于: https://try.redis.io/

基本介绍

Redis在数据库家族中被称为键值对存储。

键值存储的本质是在一个键中能存储一些称为值的数据。我们只有知道存储数据的键,才能够检索出这些数据。

通常,Redis 被称为数据结构服务器,因为它具有外部键值shell,但是每个值都可以包含复杂的数据结构,例如字符串、列表、散列或称为排序集的有序数据结构以及超级日志(hyperloglog)这样的概率数据结构。

作为第一个示例,我们可以使用命令 SET 将值“fido”存储在键“server:name”处:

SET server:name "fido"

Redis 将永久存储我们的数据,因此我们稍后可以问“键server:name 中存储的值是什么?” Redis 会回复“fido”:

GET server:name => "fido"

有一个命令可以测试给定键是否存在:

EXISTS server:name => 1
EXISTS server:blabla => 0

DEL是Redis用来删除给定的键和关联的值一个基本操作, INCR以原子方式递增存储在给定键上的数字:

SET connections 10
INCR connections => 11
INCR connections => 12
DEL connections
INCR connections => 1

还可以将键中包含的数字增加特定数量:

INCRBY connections 100 => 101

并且有类似的命令可以减少键的值。

DECR connections => 100
DECRBY connections 10 => 90

当您使用递增和递减命令操作 Redis 字符串时,您正在实现计数器。 计数器是 Redis 非常流行的应用程序。

INCR 有一些特别之处。 如果我们自己用一点代码就可以完成,为什么要提供这样的操作呢? 毕竟它很简单:

x = GET count
x = x + 1
SET count x

问题是,以这种方式进行增量只会在只有一个客户端使用键时才有效。 看看如果两个客户端同时访问这个键会发生什么:

  1. 客户端 A 读取count为 10。
  2. 客户端 B 读取count为 10。
  3. 客户端 A 增加 10 并将count设置为 11。
  4. 客户端 B 增加 10 并将count设置为 11。

我们希望值是 12,但它是 11! 这是因为以这种方式增加值不是原子操作。 在 Redis 中调用 INCR 命令将防止这种情况发生,因为它是一个原子操作。

单个命令实现的所有Redis操作都是原子的,包括对更复杂数据结构的操作。 因此,当您使用修改某些值的 Redis 命令时,您不必考虑并发访问。

Redis 可以被告知一个键应该只存在一定的时间长度。这是通过 EXPIRE 和 TTL 命令以及类似的 PEXPIRE 和 PTTL 命令来实现的。PEXPIRE 和 PTTL命令使用时间以毫秒而不是秒为单位进行操作。

SET resource:lock "Redis Demo"
EXPIRE resource:lock 120

这会导致在 120 秒内删除键resource:lock。您可以使用 TTL 命令测试键将存在多长时间。它返回将被删除之前的秒数。

TTL resource:lock => 113
// after 113s
TTL resource:lock => -2

键的 TTL 的 -2 表示键不存在(不再存在)。 键的 TTL 为 -1 意味着它永远不会过期。 请注意,如果您设置一个键,它的 TTL 将被重置。

SET resource:lock "Redis Demo 1"
EXPIRE resource:lock 120
TTL resource:lock => 119
SET resource:lock "Redis Demo 2"
TTL resource:lock => -1

SET 命令实际上能够接受更多参数,以便直接为键设置生存时间 (TTL),因此您可以在单个原子操作中更改键的值并同时设置其 TTL:

SET resource:lock "Redis Demo 3" EX 5
TTL resource:lock => 5

也可以取消键的生存时间,删除过期设置并再次使键永久。

SET resource:lock "Redis Demo 3" EX 5
PERSIST resource:lock
TTL resource:lock => -1

关于列表

Redis 还支持几种更复杂的数据结构。 我们要看的第一个是一个列表。 列表是一系列有序值。 与列表交互的一些重要命令是 RPUSH、LPUSH、LLEN、LRANGE、LPOP 和 RPOP。 您可以立即开始使用作为列表的键,只要它尚未作为其他类型存在。

这个概念通常适用于每个 Redis 数据结构:您不必先创建一个键,然后再向其添加内容,但您可以直接使用该命令来添加新元素。 作为副作用,如果键不存在,则将创建该键。 类似地,在执行某些命令后将导致空的键将自动从键空间中删除。

RPUSH 将新元素放在列表的末尾。

RPUSH friends "Alice"
RPUSH friends "Bob"

LPUSH 将新元素放在列表的开头。

LPUSH friends "Sam"

LRANGE 给出了列表的一个子集。 它将您要检索的第一个元素的索引作为其第一个参数,并将您要检索的最后一个元素的索引作为其第二个参数。 第二个参数的值 -1 表示检索元素直到列表末尾,-2 表示包括倒数第二个,依此类推。

LRANGE friends 0 -1 => 1) "Sam", 2) "Alice", 3) "Bob"
LRANGE friends 0 1 => 1) "Sam", 2) "Alice"
LRANGE friends 1 2 => 1) "Alice", 2) "Bob"

到目前为止,我们探索了让您向列表添加元素的命令,以及让您检查列表范围的 LRANGE。 Redis 列表的一个基本功能是能够删除列表的头部或尾部元素,并同时将其返回给客户端。

LPOP 从列表中删除第一个元素并返回它。

LPOP friends => "Sam"

RPOP 从列表中删除最后一个元素并返回它。

RPOP friends => "Bob"

请注意,列表现在只有一个元素:

LLEN friends => 1
LRANGE friends 0 -1 => 1) "Alice"

RPUSH 和 LPUSH 命令都是可变参数,因此您可以在同一命令执行中指定多个元素。

RPUSH friends 1 2 3 => 4

提示:RPUSH 和 LPUSH 返回操作后列表的总长度。

您还可以使用 LLEN 获取列表的当前长度。

LLEN friends => 4

关于集合

我们将研究的下一个数据结构是集合。 集合类似于列表,但它没有特定的顺序,每个元素只能出现一次。 这两种数据结构都非常有用,因为虽然在列表中可以快速访问顶部或底部附近的元素,并且元素的顺序被保留,但在集合中测试成员资格非常快,即立即 知道是否添加了给定元素。 此外,在一个集合中,一个给定的元素只能存在于一个副本中。

使用集合的一些重要命令是 SADD、SREM、SISMEMBER、SMEMBERS 和 SUNION。

SADD 将给定的成员添加到集合中,同样这个命令也是可变参数。

SADD superpowers "flight"
SADD superpowers "x-ray vision" "reflexes"

SREM 从集合中删除给定成员,返回 1 或 0 以表示该成员是否实际存在。

SREM superpowers "reflexes" => 1
SREM superpowers "making pizza" => 0

SISMEMBER 测试给定的值是否在集合中。 如果值存在则返回 1,否则返回 0。

SISMEMBER superpowers "flight" => 1
SISMEMBER superpowers "reflexes" => 0

SMEMBERS 返回该集合的所有成员的列表。

SMEMBERS superpowers => 1) "flight", 2) "x-ray vision"

SUNION 组合两个或多个集合并返回所有元素的列表。

SADD birdpowers "pecking"
SADD birdpowers "flight"
SUNION superpowers birdpowers => 1) "pecking", 2) "x-ray vision", 3) "flight"

SADD 的返回值与 SREM 的返回值一样重要。 如果我们尝试添加的元素已经在里面,则返回 0,否则 SADD 返回 1:

SADD superpowers "flight" => 0
SADD superpowers "invisibility" => 1

集合也有一个与 LPOP 和 RPOP 非常相似的命令,以便从集合中提取元素并将它们在单个操作中返回给客户端。 然而,由于集合不是有序的数据结构,因此在这种情况下返回(和删除)的元素是完全随意的。

SADD letters a b c d e f => 6
SPOP letters 2 => 1) "c" 2) "a"

键名后的 SPOP 参数是我们希望它返回并从集合中删除的元素数。

现在该集合将只有剩余的元素:

SMEMBERS letters => 1) "b" 2) "d" 3) "e" 4) "f"

还有一个命令可以返回随机元素而不从集合中删除这些元素,它被称为 SRANDMEMBER。 你可以自己试试,参数和SPOP类似,但是如果你指定负数而不是正数,它也可能返回重复元素。

有序集合

集合是一种非常方便的数据类型,但由于它们是未排序的,因此它们不能很好地解决许多问题。 这就是 Redis 1.2 引入 Sorted Sets 的原因。

有序集合类似于常规集合,但现在每个值都有一个关联的分数。 该分数用于对集合中的元素进行排序。

ZADD hackers 1940 "Alan Kay"
ZADD hackers 1906 "Grace Hopper"
ZADD hackers 1953 "Richard Stallman"
ZADD hackers 1965 "Yukihiro Matsumoto"
ZADD hackers 1916 "Claude Shannon"
ZADD hackers 1969 "Linus Torvalds"
ZADD hackers 1957 "Sophie Wilson"
ZADD hackers 1912 "Alan Turing"

在这些例子中,分数是出生年份,值是著名黑客的名字。

ZRANGE hackers 2 4 => 1) "Claude Shannon", 2) "Alan Kay", 3) "Richard Stallman"

Hashes

简单的字符串、集合和排序集合已经完成了很多工作,但 Redis 还可以处理另一种数据类型:哈希。

哈希是字符串字段和字符串值之间的映射,因此它们是表示对象的完美数据类型(例如:具有姓名、姓氏、年龄等多个字段的用户):

HSET user:1000 name "John Smith"
HSET user:1000 email "john.smith@example.com"
HSET user:1000 password "s3cret"

要取回保存的数据,请使用 HGETALL:

HGETALL user:1000

您还可以一次设置多个字段:

HMSET user:1001 name "Mary Jones" password "hidden" email "mjones@example.com"

如果您只需要一个可能的字段值:

HGET user:1001 name => "Mary Jones"

散列字段中的数值的处理方式与简单字符串中的完全相同,并且有一些操作可以以原子方式增加该值。

HSET user:1000 visits 10
HINCRBY user:1000 visits 1 => 11
HINCRBY user:1000 visits 10 => 21
HDEL user:1000 visits
HINCRBY user:1000 visits 1 => 1

一些链接

可以查看以下链接以继续了解 Redis。

  1. Redis Documentation
  2. Command Reference
  3. Implement a Twitter Clone in Redis
  4. Introduction to Redis Data Types