Redis命令
Redis 命令用于在 redis 服务上执行操作。
要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。
语法
Redis 客户端的基本语法为:
1 | redis-cli |
实例
以下实例讲解了如何启动 redis 客户端:
启动 redis 客户端,打开终端并输入命令 redis-cli。该命令会连接本地的 redis 服务。连接到本地的 redis 服务并执行 PING 命令,该命令用于检测 redis 服务是否启动。
1 | redis-cli |
在远程服务上执行命令
如果需要在远程 Redis
服务上执行命令,同样我们使用的也是 redis-cli
命令。和上面实例类似,上述命令执行的是默认参数,host
为 127.0.0.1
,port
为 6379
, 无需密码
1 | $ redis-cli -h host -p port -a password |
实例
以下实例演示了如何连接到主机为 127.0.0.1,端口为 6379 ,密码为 mypass 的 redis 服务上。
1 | redis-cli -h 127.0.0.1 -p 6379 -a "mypass" |
语法
1 | redis-cli -h host -p port -a password |
实例
以下实例演示了如何连接到主机为 127.0.0.1,端口为 6379 ,密码为 mypass 的 redis 服务上。
1 | redis-cli -h 127.0.0.1 -p 6379 -a "mypass" |
Redis 键(key)相关命令
Redis 键命令用于管理 redis 的键。
语法
Redis 键命令的基本语法如下:
1 | 127.0.0.1:6379> COMMAND KEY_NAME |
实例
1 | # del 是一个命令, name 是一个键。如果键被删除成功,命令执行后输出 (integer) 1,否则将输出 (integer) 0 |
Redis键相关的基本命令
命令 | 描述 | 可用版本 |
---|---|---|
del key | 该命令用于在 key 存在时删除 key。返回被删除 key 的数量 | >= 1.0.0 |
dump key | 该命令用于序列化给定 key 。如果 key 不存在,那么返回 nil 。 否则,返回序列化之后的值。 | >= 2.6.0 |
exists key | 该命令用于检查给定 key 是否存在。若 key 存在返回 1 ,否则返回 0 。 | >= 1.0.0 |
expire key seconds | 1. 该命令用于设置 key 的过期时间,key 过期后将不再可用。单位以秒计。设置成功返回 1 。 当 key 不存在或者不能为 key 设置过期时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的过期时间)返回 0 。在 Redis 2.1.3 之前的版本中,修改一个带有生存时间的 key 会导致整个 key 被删除,这一行为是受当时复制(replication)层的限制而作出的,现在这一限制已经被修复。2. 在 Redis 2.4 版本中,过期时间的延迟在 1 秒钟之内 —— 也即是,就算 key 已经过期,但它还是可能在过期之后一秒钟之内被访问到,而在新的 Redis 2.6 版本中,延迟被降低到 1 毫秒之内。 | >= 1.0.0 |
pexpire key milliseconds | 该命令和 expire 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间。 | >= 2.6.0 |
expireat key timestamp | 该命令用于以 UNIX 时间戳(unix timestamp)格式设置 key 的过期时间,单位以秒计。key 过期后将不再可用。设置成功返回 1 。当 key 不存在或者不能为 key 设置过期时间时返回 0 。 | >= 1.2.0 |
pexpireat key milliseconds-timestamp | 该命令和expireat 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳。 | >= 2.6.0 |
keys pattern | 1. 该命令用于查找所有符合给定模式 pattern 的 key 。时间复杂度:O(N), N 为数据库中 key 的数量。返回符合给定模式的 key 列表。2. keys 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替。 | >= 1.0.0 |
move key db | 1. 该命令用于将当前数据库的 key 移动到给定的数据库 db 当中。时间复杂度:O(1)。移动成功返回 1 ,失败则返回 0 。2. 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。因此,也可以利用这一特性,将 move 当作锁(locking)原语(primitive)。 | >= 1.0.0 |
persist key | 该命令用于移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。时间复杂度:O(1)。当生存时间移除成功时,返回 1 .如果 key 不存在或 key 没有设置生存时间,返回 0 。 | >= 2.2.0 |
ttl key | 1. 该命令以秒为单位返回 key 的剩余过期时间。当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。时间复杂度:O(1) 2. 在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。 | >= 1.0.0 |
pttl key | 1. 该命令以毫秒为单位返回 key 的剩余过期时间。当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。时间复杂度:O(1) 2. 在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。 | >= 2.6.0 |
randomkey | 该命令从当前数据库中随机返回(不删除)一个 key 。时间复杂度:O(1)。当数据库不为空时,返回一个 key 。当数据库为空时,返回 nil 。 | >= 1.0.0 |
rename key newkey | 将 key 改名为 newkey 。时间复杂度:O(1)。改名成功时提示 OK ,当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。当 newkey 已经存在时, raname 命令将覆盖旧值。 | >= 1.0.0 |
renamenx key newkey | 将 key 改名为 newkey 。时间复杂度:O(1)。当且仅当 newkey 不存在时,将 key 改名为 newkey 。修改成功时,返回 1 。当 newkey 存在时,返回 0 。当 key 不存在时,返回一个错误。 | >= 1.0.0 |
type key | 返回 key 所储存的值的类型。时间复杂度:O(1)。none (key不存在)string (字符串)list (列表)set (集合)zset (有序集)hash (哈希表) | >= 1.0.0 |
Redis键相关的其他命令
sort
语法
sort key [by pattern] [limit offset count] [get pattern [get pattern ...]] [asc | desc] [alpha] [store destination]
返回或保存给定列表、集合、有序集合 key 中经过排序的元素。排序默认以数字作为对象,值被解释为双精度浮点数,然后进行比较。
一般 SORT 用法
最简单的 SORT 使用方法是 SORT key 和 SORT key DESC :
sort key
返回键值从小到大排序的结果。sort key desc
返回键值从大到小排序的结果。
1 | 127.0.0.1:6379> lpush cost 20 18 35 9.3 18 |
使用外部 key 进行排序
可以使用外部 key 的数据作为权重,代替默认的直接对比键值的方式来进行排序。
假设现在有用户数据如下:
uid | user_name_{uid} | user_level_{uid} |
---|---|---|
1 | admin | 9999 |
2 | jack | 10 |
3 | peter | 25 |
1 | 127.0.0.1:6379> lpush uid 1 |
默认情况下, SORT uid 直接按 uid 中的值排序,通过使用 BY 选项,可以让 uid 按其他键的元素来排序。
user_level_* 是一个占位符, 它先取出 uid 中的值, 然后再用这个值来查找相应的键。
比如在对 uid 列表进行排序时, 程序就会先取出 uid 的值 1 、 2 、 3 , 然后使用 user_level_1 、 user_level_2 、 user_level_3的值作为排序 uid 的权重。
get 选项
使用get
选项, 可以根据排序的结果来取出相应的键值。
1 | 127.0.0.1:6379> sort uid get user_name_* |
组合使用 by 和 get
通过组合使用by
和get
, 可以让排序结果以更直观的方式显示出来。
比如说, 以下代码先按 user_level_{uid} 来排序 uid 列表, 再取出相应的 user_name_{uid} 的值:
1 | 127.0.0.1:6379> sort uid by user_level_* get user_name_* |
获取多个外部键
可以同时使用多个get
选项, 获取多个外部键的值。get
有一个额外的参数规则——可以用 # 获取被排序键的值。
1 | 127.0.0.1:6379> sort uid get # get user_level_* get user_name_* |
获取外部键,但不进行排序
通过将一个不存在的键作为参数传给by
选项, 可以让sort
跳过排序操作, 直接返回结果:
1 | 127.0.0.1:6379> sort uid by not-exists-key |
这种用法在单独使用时,没什么实际用处。
不过,通过将这种用法和get
选项配合, 就可以在不排序的情况下, 获取多个外部键, 相当于执行一个整合的获取操作(类似于 SQL 数据库的 join 关键字)。
1 | 127.0.0.1:6379> sort uid by not-exists-key get # get user_level_* get user_name_* |
保存排序结果
默认情况下, sort
操作只是简单地返回排序结果,并不进行任何保存操作。
通过给store
选项指定一个 key 参数,可以将排序结果保存到给定的键上。
如果被指定的 key 已存在,那么原有的值将被排序结果覆盖。
1 | 127.0.0.1:6379> rpush numbers 1 3 5 7 9 |
可以通过将sort
命令的执行结果保存,并用expire
为结果设置生存时间,以此来产生一个sort
操作的结果缓存。
这样就可以避免对sort
操作的频繁调用:只有当结果集过期时,才需要再调用一次sort
操作。
另外,为了正确实现这一用法,你可能需要加锁以避免多个客户端同时进行缓存重建(也就是多个客户端,同一时间进行sort
操作,并保存为结果集),具体参见setnx
命令。
object
object subcommand [arguments [arguments]]
object
命令允许从内部察看给定key
的 Redis 对象。
它通常用在除错(debugging)或者了解为了节省空间而对 key 使用特殊编码的情况。
当将Redis用作缓存程序时,你也可以通过 OBJECT 命令中的信息,决定 key 的驱逐策略(eviction policies)。
可用版本:>= 2.2.3 ,时间复杂度:O(1)。
object 命令子命令
object refcount key
返回给定 key 引用所储存的值的次数。此命令主要用于除错。object encoding key
返回给定 key 锁储存的值所使用的内部表示(representation)。object idletime key
返回给定 key 自储存以来的空转时间(idle, 没有被读取也没有被写入),以秒为单位。
对象编码方式:
- 字符串可以被编码为
raw
(一般字符串)、embstr
或int
(用字符串表示64位数字是为了节约空间)。 - 列表可以被编码为
ziplist
或linkedlist
。ziplist
是为节约大小较小的列表空间而作的特殊表示。 - 集合可以被编码为
intset
或者hashtable
。intset
是只储存数字的小集合的特殊表示。 - 哈希表可以编码为
zipmap
或者hashtable
。zipmap
是小哈希表的特殊表示。
有序集合可以被编码为 ziplist 或者 skiplist 格式。 ziplist 用于表示小的有序集合,而 skiplist 则用于表示任何大小的有序集合。
示例
1 | 127.0.0.1:6379> set name "redis" |
具体为什么是44而不是其他数字,原因可参考
为什么redis小等于39字节的字符串是embstr编码,大于39是raw编码? 44和39只是因为版本支持不同,github修改记录可参考commit
restore
restore key ttl serialized-value
反序列化给定的序列化值,并将它和给定的key
关联。与dump
相对应。可用版本:>= 2.6.0
参数ttl
以毫秒为单位为key
设置生存时间;如果ttl
为 0 ,那么不设置生存时间。
restore
在执行反序列化之前会先对序列化值的 RDB 版本和数据校验和进行检查,如果 RDB 版本不相同或者数据不完整的话,那么restore
会拒绝进行反序列化,并返回一个错误。
时间复杂度
- 查找给定键的复杂度为 O(1) ,对键进行反序列化的复杂度为 O(N*M) ,其中 N 是构成 key 的 Redis 对象的数量,而 M 则是这些对象的平均大小。
- 有序集合(sorted set)的反序列化复杂度为 O(NMlog(N)) ,因为有序集合每次插入的复杂度为 O(log(N)) 。
- 如果反序列化的对象是比较小的字符串,那么复杂度为 O(1) 。
示例
1 | 127.0.0.1:6379> set hi "Hello, World!" |
migrate
migrate host port key destination-db timeout [copy] [replace]
将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除。可用版本:>= 2.6.0。迁移成功时返回 OK ,否则返回相应的错误。
这个命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等到超时。
可选项:
copy
:不移除源实例上的 key 。replace
:替换目标实例上已存在的 key 。
内部实现
它在当前实例对给定 key 执行dump
命令 ,将它序列化,然后传送到目标实例,目标实例再使用restore
对数据进行反序列化,并将反序列化所得的数据添加到数据库中;当前实例就像目标实例的客户端那样,只要看到restore
命令返回 OK ,它就会调用del
删除自己数据库上的 key 。
timeout 参数以毫秒为格式,指定当前实例和目标实例进行沟通的最大间隔时间。这说明操作并不一定要在 timeout 毫秒内完成,只是说数据传送的时间不能超过这个 timeout 数。
migrate
命令需要在给定的时间规定内完成 IO 操作。如果在传送数据时发生 IO 错误,或者达到了超时时间,那么命令会停止执行,并返回一个特殊的错误: IOERR 。
当 IOERR 出现时,有以下两种可能:
- key 可能存在于两个实例
- key 可能只存在于当前实例
唯一不可能发生的情况就是丢失 key ,因此,如果一个客户端执行 MIGRATE 命令,并且不幸遇上 IOERR 错误,那么这个客户端唯一要做的就是检查自己数据库上的 key 是否已经被正确地删除。
如果有其他错误发生,那么 MIGRATE 保证 key 只会出现在当前实例中。(当然,目标实例的给定数据库上可能有和 key 同名的键,不过这和 MIGRATE 命令没有关系)。
时间复杂度:
这个命令在源实例上实际执行 DUMP 命令和 DEL 命令,在目标实例执行 RESTORE 命令,查看以上命令的文档可以看到详细的复杂度说明。
key 数据在两个实例之间传输的复杂度为 O(N) 。
实例
- 启动两个Redis实例,一个默认 6379 端口,一个 9999 接口
1 | $ ./redis-server --port 9999 |
- 用客户端连上 6379 端口的实例,设置一个键,然后将它迁移到 7777 端口的实例上
1 | ./redis-cli |
- 使用另一个客户端,查看 9999 端口上的实例
1 | $ ./redis-cli -p 9999 |
scan
scan cursor [MATCH pattern] [COUNT count]
scan
命令是一个基于游标的迭代器(cursor based iterator): scan
命令每次被调用之后,都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数,以此来延续之前的迭代过程。当scan
命令的游标参数被设置为 0 时,服务器将开始一次新的迭代,而当服务器向用户返回值为 0 的游标时,表示迭代已结束。
MATCH 选项
和keys
命令一样,增量式迭代命令也可以通过提供一个 glob 风格的模式参数,让命令只返回和给定模式相匹配的元素,这一点可以通过在执行增量式迭代命令时,通过给定 MATCH
TODO 不是很明白,回头继续
Redis 字符串(String)相关命令
Redis 字符串数据类型的相关命令用于管理 redis 字符串值,基本语法如下:
语法
1 | 127.0.0.1:6379> COMMAND KEY_NAME |
实例
1 | 127.0.0.1:6379> set name redis |
Redis字符串(String)相关的基本命令
命令 | 描述 | 时间复杂度 | 可用版本 |
---|---|---|---|
set key value | 1. 将字符串值 value 关联到 key 。如果 key 已经持有其他值, set 就覆写旧值,无视类型。对于某个原本带有生存时间(TTL)的键来说, 当set 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。2. 在 Redis 2.6.12 以前版本, set 命令总是返回 OK 。从 Redis 2.6.12 版本开始,set 在设置操作成功完成时,才返回 OK 。如果设置了 NX 或者 XX ,但因为条件没达到而造成设置操作未执行,那么命令返回空批量回复(NULL Bulk Reply)。3. 从 Redis 2.6.12 版本开始, set 命令的行为可以通过一系列参数来修改:EX 、PX 、NX 、XX 。http://doc.redisfans.com/string/set.html | O(1) | >= 1.0.0 |
get key | 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。假如 key 储存的值不是字符串类型,返回一个错误,因为get 只能用于处理字符串值。 | O(1) | >= 1.0.0 |
getrange key start end | 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。getrange 通过保证子字符串的值域(range)不超过实际字符串的值域来处理超出范围的值域请求。 | O(N), N 为要返回的字符串的长度。复杂度最终由字符串的返回值长度决定,但因为从已有字符串中取出子字符串的操作非常廉价(cheap),所以对于长度不大的字符串,该操作的复杂度也可看作O(1)。 | >= 2.4.0 |
getset key value | 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。key 不存在时,返回 nil 。 | O(1) | >= 1.0.0 |
incr key | 1. 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行incr 操作,返回执行命令之后 key 的值。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。2. 本操作的值限制在 64 位(bit)有符号数字表示之内。这是一个针对字符串的操作,因为 Redis 没有专用的整数类型,所以 key 内储存的字符串被解释为十进制 64 位有符号整数来执行 incr 操作。3. 限速器与计数器的应用。 4. incrby key increment 、incrbyfloat key increment 、decr key 、decrby key decrement 命令与之类似。http://doc.redisfans.com/string/incrbyfloat.html | O(1) | >= 1.0.0 |
getbit key offset | 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。 | O(1) | >= 2.2.0 |
setbit key offset value | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。当 key 不存在时,自动生成一个新的字符串值。字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。2. offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。对使用大的 offset 的 setbit 操作来说,内存分配可能造成 Redis 服务器被阻塞。具体参考setrange 命令,warning(警告)部分。 | O(1) | >= 2.2.0 |
strlen key | 返回 key 所储存的字符串值的长度。当 key 不存在时,返回 0 。当 key 储存的不是字符串值时,返回一个错误。 | O(1) | >= 2.2.0 |
mget key [key ...] | 返回所有(一个或多个)给定 key 的值。如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。 | O(N) , N 为给定 key 的数量。 | >= 1.0.0 |
mset key value [key value ...] | 1. 同时设置一个或多个 key-value 对。如果某个给定 key 已经存在,那么mset 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用msetnx 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。2. mset 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。总是返回 OK (因为 MSET 不可能失败) | O(N), N 为要设置的 key 数量。 | >= 1.0.1 |
msetnx key value [key value ...] | 1. 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。即使只有一个给定 key 已存在, msetnx 也会拒绝执行所有给定 key 的设置操作。当所有 key 都成功设置,返回 1 。如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。2. msetnx 是原子性的,因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object),所有字段要么全被设置,要么全不被设置。 | O(N), N 为要设置的 key 数量。 | >= 1.0.1 |
append key value | 1. 如果 key 已经存在并且是一个字符串, append 命令将 value 追加到 key 原来的值的末尾。如果 key 不存在, append 就简单地将给定 key 设为 value ,就像执行 set key value 一样。2. 返回追加 value 之后, key 中字符串的长度。 | 平摊O(1) | >= 2.0.0 |
Redis字符串(String)相关的其他命令
bitcount
bitcount key [start] [end]
计算给定字符串中,被设置为 1 的比特位的数量。
一般情况下,给定的整个字符串都会被进行计数,通过指定额外的start
或 end
参数,可以让计数只在特定的位上进行。
start
和end
参数的设置和getrange
命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
可用版本:>= 2.6.0,时间复杂度:O(N)
示例
1 | 127.0.0.1:6379> bitcount bits |
使用 bitmap 实现用户上线次数统计
Bitmap 对于一些特定类型的计算非常有效。
假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT 和 BITCOUNT 来实现。
比如说,每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。
举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。
当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。
更详细的实现可以参考博文(墙外) Fast, easy, realtime metrics using Redis bitmaps 。
性能
前面的上线次数统计例子,即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, BITCOUNT 的处理速度就像 GET 和 INCR 这种 O(1) 复杂度的操作一样快。
如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:
将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
使用 BITCOUNT 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。
更详细的实现可以参考博文 REDIS BITMAPS – FAST, EASY, REALTIME METRICS
bitop
bitop operation destkey key [key ...]
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:
bitop add destkey key [key ...]
,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。bitop or destkey key [key ...]
,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。bitop xor destkey key [key ...]
,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。bitop not destkey key
,对给定 key 求逻辑非,并将结果保存到 destkey 。
除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。
处理不同长度的字符串
当bitop
处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0 。空的 key 也被看作是包含 0 的字符串序列。
可用版本:>= 2.6.0,时间复杂度:O(N),返回值:保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。
bitop
的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。
示例
1 | 127.0.0.1:6379> setbit bits-1 0 1 # 1001 |
setrange
setrange key offset value
用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。可用版本:>= 2.2.0。返回被setrange
修改之后,字符串的长度。
setrange
命令会确保字符串足够长以便将 value 设置在指定的偏移量上,不存在的 key 当作空白字符串处理。如果给定 key 原来储存的字符串长度比偏移量小,那么原字符和偏移量之间的空白将用零字节(zerobytes, “\x00” )来填充。
注意
你能使用的最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间,你可以使用多个 key 。
时间复杂度:
对小(small)的字符串,平摊复杂度O(1)(关于什么字符串是”小”的,请参考 append
命令)。否则为O(M), M 为 value 参数的长度。
实例
1 | $ # 对非空字符串进行 setrange |
模式
因为有了setrange
和getrange
命令,你可以将 Redis 字符串用作具有O(1)随机访问时间的线性数组,这在很多真实用例中都是非常快速且高效的储存方式,具体请参考append
命令的『模式:时间序列』部分。
append
append key value
append key value
之后,返回 key 中字符串的长度。如果 key 已经存在并且是一个字符串,append
命令将 value 追加到 key 原来的值的末尾。如果 key 不存在,append
就简单地将给定 key 设为 value ,就像执行 set key value
一样。可用版本:>= 2.0.0。时间复杂度:平摊O(1)。
实例
1 | 127.0.0.1:6379> exists money |
时间序列(Time series)
append
可以为一系列定长(fixed-size)数据(sample)提供一种紧凑的表示方式,通常称之为时间序列。
每当一个新数据到达的时候,执行命令:append timeseries "fixed-size sample"
然后可以通过以下的方式访问时间序列的各项属性:
strlen
给出时间序列中数据的数量- getrange 可以用于随机访问。只要有相关的时间信息的话,我们就可以在 Redis 2.6 中使用 Lua 脚本和 GETRANGE 命令实现二分查找。
setrange
可以用于覆盖或修改已存在的的时间序列。
这个模式的唯一缺陷是我们只能增长时间序列,而不能对时间序列进行缩短,因为 Redis 目前还没有对字符串进行修剪(tirm)的命令,但是,不管怎么说,这个模式的储存方式还是可以节省下大量的空间。
可以考虑使用 UNIX 时间戳作为时间序列的键名,这样一来,可以避免单个 key 因为保存过大的时间序列而占用大量内存,另一方面,也可以节省下大量命名空间。
set
set key value [EX seconds] [PX milliseconds] [NX|XX]
- 将字符串值 value 关联到 key 。如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
- 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
可选参数
从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
EX second
:设置键的过期时间为 second 秒。set key value EX second
效果等同于setex key second value
。PX millisecond
:设置键的过期时间为 millisecond 毫秒。set key value PX millisecond
效果等同于psetex key millisecond value
。NX
:只在键不存在时,才对键进行设置操作。set key value NX
效果等同于setnx key value
。XX
:只在键已经存在时,才对键进行设置操作。
返回值
- 在 Redis 2.6.12 版本以前, SET 命令总是返回 OK 。
- 从 Redis 2.6.12 版本开始, SET 在设置操作成功完成时,才返回 OK 。如果设置了 NX 或者 XX ,但因为条件没达到而造成设置操作未执行,那么命令返回空批量回复(NULL Bulk Reply)。
使用模式
命令 set resource-name anystring NX EX max-lock-time
是一种在 Redis 中实现锁的简单方法。
客户端执行以上的命令:
- 如果服务器返回 OK ,那么这个客户端获得锁。
如果服务器返回 NIL ,那么客户端获取锁失败,可以在稍后再重试。 - 设置的过期时间到达之后,锁将自动释放。
可以通过以下修改,让这个锁实现更健壮:
不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)。
不使用 DEL 命令来释放锁,而是发送一个 Lua 脚本,这个脚本只在客户端传入的值和键的口令串相匹配时,才对键进行删除。
这两个改动可以防止持有过期锁的客户端误删现有锁的情况出现。
1 | if redis.call("get", KEYS[1]) == ARGV[1] |