redis:与键相关的命令

redis是一种key-value型数据库,它将数据全部以键值对的形式存储在内存中,并且key与value一一对应。这里的key被形象的称之为密钥,redis提供了很多操作这把“密钥”的命令,从而实现了对存储数据的管理

key的特点

key的类型

key 的类型对应着 value 的类型,同样也有五种(string、list、hash、set、zset)。如果 key 指向的是一个字符串类型的值,那么 key 的类型就是字符串。我们可以通过TYPE命令来查看 key 的类型。

也就是说,type命令实际返回的就是当前键的数据结构类型,它们分别是:string、list、hash、set、zset,但这些只是redis对外的数据结构,如下图:
在这里插入图片描述
实际上每种数据结构都有自己底层的不止一种的内部编码实现,redis会根据场景选择合适的内部编码。通过object encoding [key] 可以查看内部编码

127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> object encoding mylist
"ziplist"

这样设计的好处:

  • 可以改进内部编码,对外的数据结构和命名没有影响,这样一旦开发出了更优秀的编码,无需改动外部数据结构和命令
  • 多种内部编码可以在不同的场景下发挥各自有时。比如ziplist比较节约内存,但在元素比较多的时候,性能会下降,此时转换为linkedlist。
    在这里插入图片描述

key的命名规范

key的命名需要遵循如下规则

  • key取值不可以太长,否则会影响value的查找效率,并且浪费内存空间
  • key取值也不可以过短,否则会使得key可读性变差

在 key 的取值上, Redis 官方建议使用“见名知意”的字符串格式,因为这样便于我们理解 key 的含义。比如要现在存放一个用户的姓名,其信息如下:
在这里插入图片描述
我们使用一个 key 来存储用户的名字,key 的设置如下所示:

127.0.0.1:6379> set user:id:01:username XiaoHong
OK

上述示例,自定义了uesr:id:01:username这个 key,通过 key 不仅可以知道用户的 id,还可以知道这个 key 是用来存储用户名字的。注意,这里的:只是起到分割符的作用,并不是固定的语法格式。

在redis中,我们也可以将一个空字符串设置成key,示例如下:

127.0.0.1:6379> SET "" c.biancheng.net
OK
127.0.0.1:6379> GET ""
"c.biancheng.net"

key的类型并不局限于字符串,在redis中key具有二进制安全的特性,这意味着它可以使用任何二进制序列,但是这种key过于复杂一般不建议采用。

key过期时间

redis允许为key设置一个过期时间,也就是“到点自动删除”。这在实际业务中是非常有用的:

  • 一是它可以避免使用频率不高的 key 长期存在,从而占用内存资源;
  • 二是控制缓存的失效时间。

Redis 会把每个设置了过期时间的 key 存放到一个独立的字典中,并且会定时遍历这个字典来删除到期的 key。

除了定时遍历之外,它还会使用“惰性策略”来删除过期的key。所谓“惰性策略”指的是当客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除。

redis使用两种相结合的方法去处理过去的key。

与Key相关的命令

和 key 相关的命令,它的语法格式如下所示:

redis 127.0.0.1:6379> COMMAND KEY_NAME
  • COMMAND:表示 key 的命令;
  • KEY_NAME:表示 key 的名字。

下表对常用的 Redis 键命令做了简单的总结:

命令说明
DEL key若键存在的情况下,该命令用于删除键
DUMP key用于序列化给定key,并返回被序列化的值
EXISTS key用于检查键是否存在,如果存在则返回1,否则返回0
EXPIRE key设置 key 的过期时间,以秒为单位。
EXPIREAT key该命令与 EXPIRE 相似,用于为 key 设置过期时间,不同在于,它的时间参数值采用的是时间戳格式。
PEXPIRE key设置 key 的过期,以毫秒为单位。
PEXPIREAT key与 PEXPIRE 相似,用于为 key 设置过期时间,采用以毫秒为单位的时间戳格式。
KEYS pattern此命令用于查找与指定 pattern 匹配的 key。
MOVE key db将当前数据库中的 key 移动至指定的数据库中(默认存储为 0 库,可选 1-15中的任意库)。
PERSIST key该命令用于删除 key 的过期时间,然后 key 将一直存在,不会过期。
PTTL key用于检查 key 还剩多长时间过期,以毫秒为单位。
TTL key用于检查 key 还剩多长时间过期,以秒为单位。
RANDOM KEY从当前数据库中随机返回一个 key。
RENAME key newkey修改 key 的名称。
RENAMENX key newkey如果新键名不重复,则将 key 修改为 newkey。
SCAN cursor
TYPE key该命令用于获取 value 的数据类型。

Type:键的类型

key 的类型对应着 value 的类型,同样也有五种(string、list、hash、set、zset)。如果 key 指向的是一个字符串类型的值,那么 key 的类型就是字符串。我们可以通过TYPE命令来查看 key 的类型

语法

redis 127.0.0.1:6379> TYPE KEY_NAME 

可用版本

>= 1.0.0

返回值

返回 key 的数据类型,数据类型有:

  • none (key不存在)
  • string (字符串)
  • list (列表)
  • set (集合)
  • zset (有序集)
  • hash (哈希表)

实例

# 字符串
redis> SET weather "sunny"
OK
redis> TYPE weather
string

# 列表
redis> LPUSH book_list "programming in scala"
(integer) 1
redis> TYPE book_list
list

# 集合
redis> SADD pat "dog"
(integer) 1
redis> TYPE pat
set

KEYS:查看键

作用

Keys 命令用于查找所有符合给定模式 pattern 的 key

  • KEYS * 匹配数据库中所有 key (*匹配任意字符)
  • KEYS h*llo 匹配 hllo 和 heeeeello 等 (*匹配任意字符)
  • KEYS h?llo 匹配 hello , hallo 和 hxllo 等 (?匹配一个字符)
  • KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo ([]匹配任意字符,比如[1, 3]表示匹配1和3,[1-10表示匹配1到0的任意数字])

语法

redis 127.0.0.1:6379> KEYS PATTERN

可用版本

> = 1.0.0

返回值

  • 符合给定模式的 key 列表 (Array)。

实例

redis 127.0.0.1:6379> SET runoob1 redis
OK
redis 127.0.0.1:6379> SET runoob2 mysql
OK
redis 127.0.0.1:6379> SET runoob3 mongodb
OK

查找以 runoob 为开头的 key:

redis 127.0.0.1:6379> KEYS runoob*
1) "runoob3"
2) "runoob1"
3) "runoob2"

keys * 会返回当前库中所有的键。

redis 127.0.0.1:6379> KEYS *
1) "runoob3"
2) "runoob1"
3) "runoob2"

若要删除所有以某个字符开头的键,可以执行如下操作:

# 利用Linux的管道删除
./redis-cli keys h* | xargs ./redis-cli del

使用建议

生成环境中不建议使用keys,如果确实有遍历键的需求怎么办?

  • 在一个不对外提供服务的redis从节点上执行,这样不会阻塞到客户端的请求,但是会影响到主从复制
  • 如果确认键比较少,可以执行该命令
  • 使用scan命令渐进式的遍历键,可以有效防止阻塞

scan

redis从2.8版本后,提供了一个新的命令scan,它能有效的解决keys命令存在的问题。和keys命令执行时会遍历所有键不同,scan采用渐进式遍历的方式解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度都是O(1),但是真正要实现keys的功能,需要执行多次scan

redis存储键值对实际使用的是hashtable的数据结构。每次执行scan,可以想象成只扫描一个字段中的一部分键,直到将字典中所有键遍历完毕

在这里插入图片描述

语法

SCAN 命令的语法格式如下:

SCAN cursor [MATCH pattern] [COUNT count]

参数说明:

  • cursor:是必需参数,实际上cursor是一个游标,第一次遍历从0开始,每次scan遍历完都会返回当前游标的值,直到游标值为0,表示遍历结束。
  • match pattern:是可选参数,他的作用是做模式的匹配,这点和keys的模式匹配很想。
  • count number:是可选参数,它的作用是表明每次要遍历的键个数,默认10

实例

例如当前Redis数据库中有26个键(26个英文字母),现在我们要分3次遍历完数据库中的26个键

  • 第一次执行"scan 0",返回两部分:
    • 第一部分6,代表下次scan需要的cursor
    • 第二部分是返回的11个键
127.0.0.1:6379> scan 0
1) "6"
2) 1) "w"
2) "i"
3) "e"
4) "x"
5) "j"
6) "q"
7) "y"
8) "u"
9) "b"
10) "o"
  • 第二次执行“scan 6”,因为上一次返回6,所以从“cursor=6”开始扫描,结果如下所示
127.0.0.1:6379> scan 6
1) "11"
2) 1) "h"
2) "n"
3) "m"
4) "t"
5) "c"
6) "d"
7) "g"
8) "p"
9) "z"
10) "a"
  • 第二次执行“scan 11”,因为上一次返回11,所以从“cursor=11”开始扫描,结果如下所示
127.0.0.1:6379> scan 11
1) "0"
2) 1) "s"
2) "f"
3) "r"
4) "v"
5) "k"
6) "l"
  • 上图中SCAN命令返回0,代表所有的键已经遍历完,所以遍历结束

扩展

  • 除了scan之外,Redis提供了面向哈希类型、集合类型、有序集合的扫描遍历命令。例如hgetall、smembers、zrange可能产生的阻塞问题,对应的命令分别是hscan、sscan、zscan,它们的用法和scan基本类似
  • 下面以sscan为例子进行说明, 当前集合有两种类型的元素, 例如分别以old: user和new: user开头, 先需要将old: user开头的元素全部删除, 可以参考如下伪代码:
String key = "myset";
// 定义pattern
String pattern = "old:user*";
// 游标每次从0开始
String cursor = "0";
while (true) {
// 获取扫描结果
ScanResult scanResult = redis.sscan(key, cursor, pattern);
List elements = scanResult.getResult();
if (elements != null && elements.size() > 0) {
// 批量删除
redis.srem(key, elements);
}/
/ 获取新的游标
cursor = scanResult.getStringCursor();
// 如果游标为0表示遍历结束
if ("0".equals(cursor)) {
break;
}
}

问题

  • 渐进式遍历可以有效的解决keys命令可能产生的阻塞问题,但是scan并非完美无效,如果在scan的过程中如果有键的变化(增删改),那么遍历效果可能会遇到下面问题
  • 新增的键可能没有遍历到,遍历出现重复的键等兴趣
  • 也就是说scan并不能保证完整的遍历出所有的键

Dbsize :键总数

  • Dbsize 命令用于返回当前数据库的 key 的数量。

语法

redis 127.0.0.1:6379> DBSIZE

可用版本

>= 1.0.0

返回值

  • 当前数据库的 key 的数量。

实例

redis 127.0.0.1:6379> DBSIZE
(integer) 5

redis 127.0.0.1:6379> SET new_key "hello_moto"     # 增加一个 key 试试
OK

redis 127.0.0.1:6379> DBSIZE
(integer) 6

说明

  • dbsize在计算键总数时不会遍历所有键,而是直接获取redis内置的键总数变量,其时间复杂度为O(1)
  • 而keys会遍历所有键,时间复杂度为Q(n),当redis保存了大量数据时,线上环境禁止使用keys

检测键是否存在

  • EXISTS 命令用于检查给定 key 是否存在。

语法

redis 127.0.0.1:6379> EXISTS KEY_NAME

可用版本

>= 1.0.0

返回值

  • 若 key 存在返回 1 ,否则返回 0 。

实例

redis 127.0.0.1:6379> EXISTS runoob-new-key
(integer) 0

现在我们创建一个名为 runoob-new-key 的键并赋值,再使用 EXISTS 命令。

redis 127.0.0.1:6379> set runoob-new-key newkey
OK
redis 127.0.0.1:6379> EXISTS runoob-new-key
(integer) 1
redis 127.0.0.1:6379>

删除键

  • DEL 命令用于删除已存在的键(不论数据类型如何都可以删除)。不存在的 key 会被忽略

语法

redis 127.0.0.1:6379> DEL KEY_NAME

可用版本

  • >= 1.0.0

返回值

  • 被删除 key 的数量。

实例

实例一:删除一个键

redis 127.0.0.1:6379> SET w3ckey redis
OK
redis 127.0.0.1:6379> DEL w3ckey
(integer) 1

实例二:删除多个键

dek  a b c

键过期

除了expire、ttl命令以外,Redis还提供了expireat、pexpire、pexpireat、pttl、persist等一系列命令

  • expire key seconds:键在seconds秒后过期
  • expireat key timestamp:键在秒级时间戳timestamp后过期

expire

Expire 命令用于设置 key 的过期时间,key 过期后redis将会自动删除键

语法
redis 127.0.0.1:6379> Expire KEY_NAME TIME_IN_SECONDS
可用版本

>= 1.0.0

返回值
  • 设置成功返回 1 。
  • 当 key 不存在或者不能为 key 设置过期时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的过期时间)返回 0 。
实例
redis 127.0.0.1:6379> SET runooobkey redis
OK
redis 127.0.0.1:6379> EXPIRE runooobkey 60
(integer) 1

以上实例中我们为键 runooobkey 设置了过期时间为 1 分钟,1分钟后该键会自动删除

expireat:设置过期时间

作用

Redis Expireat 命令用于以 UNIX 时间戳(unix timestamp)格式设置 key 的过期时间。key 过期后将不再可用。

语法
redis 127.0.0.1:6379> Expireat KEY_NAME TIME_IN_UNIX_TIMESTAMP
返回值
  • 设置成功返回 1 。
  • 当 key 不存在或者不能为 key 设置过期时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的过期时间)返回 0 。
实例
redis 127.0.0.1:6379> SET runoobkey redis
OK
redis 127.0.0.1:6379> EXPIREAT runoobkey 1293840000
(integer) 1

pexpire: 设置过期时间

作用

Redis PEXPIRE 命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。

语法
PEXPIRE key milliseconds
返回值
  • 设置成功,返回 1
  • key 不存在或设置失败,返回 0
实例
redis> SET mykey "Hello"
"OK"
redis> PEXPIRE mykey 1500
(integer) 1
redis> TTL mykey
(integer) 1
redis> PTTL mykey
(integer) 1498
redis> 

pexpireat: 设置过期时间

作用

这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位。

返回值

设置成功返回 1,若 key 不存在或者不能为其设置过期时间,则返回 0。

实例
127.0.0.1:6379> set www.biancheng.net Python
OK
127.0.0.1:6379> PEXPIREAT www.biancheng.net 12000000000
(integer) 1

ttl

以秒为单位返回 key 的**剩余过期时间//。

格式
redis 127.0.0.1:6379> TTL KEY_NAME
可用版本

>= 1.0.0

返回值

有三种返回值

  • -2: key 不存:
  • -1: key 存在但没有设置剩余生存时间时
  • 大于等于0的整数: key 的剩余生存时间(以秒为单位)

注意:在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。

实例
# 不存在的 key

redis> FLUSHDB
OK

redis> TTL key
(integer) -2


# key 存在,但没有设置剩余生存时间

redis> SET key value
OK

redis> TTL key
(integer) -1


# 有剩余生存时间的 key

redis> EXPIRE key 10086
(integer) 1

redis> TTL key
(integer) 10084

pttl:查询过期时间

同ttl,只是以毫秒为单位返回 key 的剩余过期时间。

注意

当使用redis相关的过期命令时,需要注意下面几点:

  • 如果expire key的键不存在,返回结果为0
127.0.0.1:6379> expire not_exist_key 30  
(integer) 0 
  • 如果过期时间为负值,键会立即被删除,犹如使用del命令一样;
127.0.0.1:6379> set hello world  
OK  
127.0.0.1:6379> expire hello -2  
(integer) 1  
127.0.0.1:6379> get hello  
(nil) 
  • persist命令可以将键的过期时间清除;
127.0.0.1:6379> hset key f1 v1  
(integer) 1  
127.0.0.1:6379> expire key 50  
(integer) 1  
127.0.0.1:6379> ttl key  
(integer) 46  
127.0.0.1:6379> persist key  
(integer) 1  
127.0.0.1:6379> ttl key  
(integer) -1 
  • 对于字符串类型键,执行set命令会去掉过期时间;

如下是Redis源码中,set命令的函数setKey,可以看到***执行了removeExpire(db,key)函数去掉了过期时间:
在这里插入图片描述
下面的例子证实了set会导致过期时间失效,因为ttl变为-1:

127.0.0.1:6379> expire hello 50  
(integer) 1  
127.0.0.1:6379> ttl hello  
(integer) 46  
127.0.0.1:6379> set hello world  
OK  
127.0.0.1:6379> ttl hello  
(integer) -1 
  • redis不支持二级数据结构(例如哈希、列表)内部元素的过期功能,例如不能对列表类型的一个元素做过期时间设置;
  • setex命令作为set+expire的组合,不但是原子执行,同时减少了一次网络通讯的时间;

rename:键重命名

作用

用于修改 key 的名称 。

语法

rename old_key_name new_key_name

返回值

  • 改名成功时提示 OK ,失败时候返回一个错误。
  • 当 old_key_name 和 new_key_name相同,或者 old_key_name 不存在时,返回一个错误。
  • 当 new_key_name已经存在时, RENAME 命令将覆盖旧值。

实例

# key 存在且 newkey 不存在

redis> SET message "hello world"
OK

redis> RENAME message greeting
OK

redis> EXISTS message               # message 不复存在
(integer) 0

redis> EXISTS greeting              # greeting 取而代之
(integer) 1


# 当 key 不存在时,返回错误

redis> RENAME fake_key never_exists
(error) ERR no such key


# newkey 已存在时, RENAME 会覆盖旧 newkey

redis> SET pc "lenovo"
OK

redis> SET personal_computer "dell"
OK

redis> RENAME pc personal_computer
OK

redis> GET pc
(nil)

redis:1> GET personal_computer      # 原来的值 dell 被覆盖了
"lenovo"

Renamenx

作用

在新的 key 不存在时修改 key 的名称 。

语法

rename old_key_name new_key_name

返回值

  • 修改成功时,返回 1 。
  • 如果 new_key_name已经存在,返回 0 。

实例

# newkey 不存在,改名成功

redis> SET player "MPlyaer"
OK

redis> EXISTS best_player
(integer) 0

redis> RENAMENX player best_player
(integer) 1


# newkey存在时,失败

redis> SET animal "bear"
OK

redis> SET favorite_animal "butterfly"
OK

redis> RENAMENX animal favorite_animal
(integer) 0

redis> get animal
"bear"

redis> get favorite_animal
"butterfly"

使用重命名时注意:

  • ·由于重命名键期间会执行del命令删除旧的键,如果键对应的值比较大,会存在阻塞Redis的可能性,这点不要忽视。
  • 如果rename和renamenx中的key和newkey如果是相同的,在Redis3.2和之前版本返回结果略有不同

randomkey:随机返回一个键

作用

从当前数据库中随机返回一个 key

语法

redis 127.0.0.1:6379> RANDOMKEY 

返回值

  • 当数据库不为空时,返回一个 key 。
  • 当数据库为空时,返回 nil (windows 系统返回 null)。

实例

# 数据库不为空

redis> MSET fruit "apple" drink "beer" food "cookies"   # 设置多个 key
OK

redis> RANDOMKEY
"fruit"

redis> RANDOMKEY
"food"

redis> KEYS *    # 查看数据库内所有key,证明 RANDOMKEY 并不删除 key
1) "food"
2) "drink"
3) "fruit"


# 数据库为空

redis> FLUSHDB  # 删除当前数据库所有 key
OK

redis> RANDOMKEY
(nil)

dump:序列化值

作用

  • 该命令用于将键对应的值做序列化处理

语法

dump key_name

返回值

  • 如果 key 不存在,那么返回 nil 。
  • 否则,返回序列化之后的值。

实例

127.0.0.1:6379> SET num 12
OK
127.0.0.1:6379> DUMP num
"\x00\xc0\x0c\t\x00\xec\xd8\xa9\x9d\b\x82\xdfd"
127.0.0.1:6379> get num
"12"
redis> DUMP not-exists-key
(nil)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值