五大数据类型及API
Redis 常用的五大数据类型,这也是开发常用的数据类型,下面我们来学习每一个数据类型和其他的 API 命令。
五大数据类型
String (字符串类型)
String 是 Redis 最基本的类型,你可以理解成 Memcached 一模一样的类型,一个 key 对应一个 value。
String 类型是二进制安全的,意思是 Redis 的 String 可以包含任何数据,比如 jpg 图片或者序列化的对象。
String 类型是 redis 最基本的数据类型,一个 Redis 中字符串 value 最多可以是 512M。
Hash(哈希,类似 Java 里的 Map)
Redis hash 是一个键值对集合。
Redis hash 是一个 String 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
类似 Java 里面的 Map
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个链表。
Set(集合)
Redis 的 Set 是 String 类型的无序集合,它是通过 HashTable 实现的。
Zset(sorted set:有序集合)
Redis zset 和 set 一样,也是 String 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。
Redis 正是通过分数来为集合中的成员进行从小到大的排序,zset 的成员是唯一的,但是分数(Score)却可以重复。
命令大小写都可以,如果你只想单纯看 API,不想看例子,请移到最下面的 指令总结。
键(key)命令
查看当前数据库的 key 的数量
dbsize
keys *
指令查看当前库所有 key
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name kele
OK
127.0.0.1:6379> keys *
1) "name"
exists key
指令判断某个 key 是否存在
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
type key
指令查看 key 的类型是哪个
127.0.0.1:6379> set name kele
OK
127.0.0.1:6379> get name
"kele"
127.0.0.1:6379> type name
string
del key
指令删除指定的 key
127.0.0.1:6379[1]> del name
(integer) 1
127.0.0.1:6379[1]> keys *
(empty array)
unlink key
指令根据 value 选择非阻塞删除(先将 keys 从 keysapce 元数据中删除,真正的删除会在后续异步操作)
127.0.0.1:6379[1]> unlink key name
(integer) 1
127.0.0.1:6379[1]> keys *
(empty array)
expire key time
指令给指定的 key 设置过期时间(time 以秒为单位),当 key 过期时(生存时间为 0 ),它会被自动删除
127.0.0.1:6379> set name kele
OK
127.0.0.1:6379> expire name 10
(integer) 1
ttl key
指令查看 key 还有多少秒过期,-1 表示永不过期,-2 表示已过期
127.0.0.1:6379> set name kele
OK
127.0.0.1:6379> expire name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) 4
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> keys *
(empty list or set)
select num
指令选择数据库,num 代表从 0-16,默认是 0
select 7
flushdb
指令清空当前库
flushdb
flushall
指令清空所有库
flushall
字符串String
单键单值
set <key> <value>
指令添加键值对:shset <key> <value>
注意,当 key 不存在,则将 key-value 存入数据库,如果存在,则覆盖原来 value
示例:Redis 的分布式锁应用
SHset lock locked nx ex 10
key 为 lock 的值 locked 在 10 秒内无法重新赋值,只有 10 秒后过期了,才能给 lock 赋值
get <key>
查看对应键值:SHget <key>
append <key> <value>
追加到原值的末尾:SHappend <key> <value>
strlen <key>
获得值的长度:SHstrlen <key>
setnx <key> <value>
指令只有 key 不存在时,才加入该 key 的值:SHsetnx <key> <value>
案例:
127.0.0.1:6379> set key1 value1 # 设置值
OK
127.0.0.1:6379> get key1 # 获得key
"value1"
127.0.0.1:6379> del key1 # 删除key
(integer) 1
127.0.0.1:6379> keys * # 查看全部的key
(empty list or set)
127.0.0.1:6379> exists key1 # 确保 key1 不存在
(integer) 0
127.0.0.1:6379> append key1 "hello" # 对不存在的 key 进行 APPEND,等同于 SET key1 "hello"
(integer) 5 # 字符长度
127.0.0.1:6379> APPEND key1 "-2333" # 对已存在的字符串进行 APPEND
(integer) 10 # 长度从 5 个字符增加到 10 个字符
127.0.0.1:6379> get key1
"hello-2333"
127.0.0.1:6379> strlen key1 # # 获取字符串的长度
(integer) 10
自增自减
incr <key>
指令将 key 中储存的数字值增 1,只能对数字值操作,如果为空,新增值为 1:SHincr <key>
decr <key>
指令将 key 中储存的数字值减 1,只能对数字值操作,如果为空,新增值为 -1:shdecr <key>
incrby / decrby <步长>
指令将 key 中储存的数字值增减。自定义步长:shincrby / decrby <步长>
案例:
127.0.0.1:6379> set views 0 # 设置浏览量为 0
OK
127.0.0.1:6379> incr views # 浏览 + 1
(integer) 1
127.0.0.1:6379> incr views # 浏览 + 1
(integer) 2
127.0.0.1:6379> decr views # 浏览 - 1
(integer) 1
127.0.0.1:6379> incrby views 10 # +10
(integer) 11
127.0.0.1:6379> decrby views 10 # -10
(integer) 1
多键多值
mset <key1> <value> <key2> <value2> ......
指令设置一个或者多个 key-value 键值对shmset <key1> <value> <key2> <value2> ......
mget <key1> <key2> ......
指令获取一个或者多个 key-value 键值对shmget <key1> <key2> ......
msetnx <key1> <value> <key2> <value2> ......
指令同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在shmsetnx <key1> <value> <key2> <value2> ......
案例:
127.0.0.1:6379> mset k10 v10 k11 v11 k12 v12
OK
127.0.0.1:6379> keys *
1) "k12"
2) "k11"
3) "k10"
127.0.0.1:6379> mget k10 k11 k12 k13
1) "v10"
2) "v11"
3) "v12"
4) (nil)
127.0.0.1:6379> msetnx k10 v10 k15 v15 # 原子性操作
(integer) 0
127.0.0.1:6379> get key15
(nil)
range范围
getrange <key> <起始位置> <结束位置>
指令获得值的范围,类似 Java 中的 substringshgetrange <key> <起始位置> <结束位置>
setrange <key> <起始位置> <value>
指令用 value 覆写所储存的字符串值,从 <起始位置> 开始(索引从 0 开始)shsetrange <key> <起始位置> <value>
案例:
127.0.0.1:6379> set key2 abcd123456 # 设置 key2 的值
OK
127.0.0.1:6379> getrange key2 0 -1 # 获得全部的值
"abcd123456"
127.0.0.1:6379> getrange key2 0 2 # 截取部分字符串
"abc"
setrange <key> <位置> <newValue>
指令设置指定区间范围内的值shsetrange <key> <位置> <newValue>
案例:
127.0.0.1:6379> get key2
"abcd123456"
127.0.0.1:6379> setrange key2 1 xx # 替换值
(integer) 10
127.0.0.1:6379> get key2
"axxd123456"
从位置 1 开始,将值替换为 xx,因为 xx 长度为 2,所以替换到位置 3 就结束了。
键值条件
setex <key> <过期时间/秒> <value>
指令设置键值的同时,设置过期时间,单位秒shsetex <key> <过期时间/秒> <value>
psetex <key> <过期时间/毫秒> <value>
指令设置键值的同时,设置过期时间,单位毫秒shpsetex <key> <过期时间/毫秒> <value>
案例:
127.0.0.1:6379> setex key3 60 expire # 设置过期时间
OK
127.0.0.1:6379> ttl key3 # 查看剩余的时间
(integer) 55
127.0.0.1:6379> setnx mykey "redis" # 如果不存在就设置,成功返回1
(integer) 1
127.0.0.1:6379> setnx mykey "mongodb" # 如果值存在则不覆盖值,返回0
(integer) 0
127.0.0.1:6379> get mykey
"redis"
getset <key> <value>
指令以新换旧,设置了新值同时获得旧值shgetset <key> <value>
案例:
127.0.0.1:6379> getset db mongodb # 没有旧值,返回 nil
(nil)
127.0.0.1:6379> get db
"mongodb"
127.0.0.1:6379> getset db redis # 返回旧值 mongodb
"mongodb"
127.0.0.1:6379> get db
"redis"
存储对象
格式:
set user:1 value(json数据)
案例:
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
案例:
java 中的 i++ 是否是原子操作?
不是。
当 i = 0 时,如果有两个线程分别对 i 进行 ++100 次,值是多少?
2-200。
列表List
List 的特点:单键多值。底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
lpush/rpush <key> <value1> <value2> <value3> ...
指令从左边 / 右边插入一个或多个值,左右也就是首尾shlpush/rpush <key> <value1> <value2> <value3> ...
例子:
shlpush k1 v1 v2 v3
lrange <key> <start> <stop>
指令按照索引下标获得元素(从左到右,先进后出)shlrange <key> <start> <stop>
lrange <key> 0 -1
指令如果 start 是 0,stop 是 -1,代表获取所有元素shlrange <key> 0 -1
案例:
127.0.0.1:6379> lpush list "one"
(integer) 1
127.0.0.1:6379> lpush list "two"
(integer) 2
127.0.0.1:6379> rpush list "right"
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> lrange list 0 1
1) "two"
2) "one"
lindex <key> <index>
指令按照索引下标获得元素(从左到右)(-1 代表最后一个,0 代表是第一个)shlindex <key> <index>
例子:
sh127.0.0.1:6379> lindex list 1 (nil) 127.0.0.1:6379> lindex list 0 "one" 127.0.0.1:6379> lindex list -1 "one"
lpop/rpop <key>
指令从左边 / 右边吐出一个值。吐出后该值就不存在 key 中shlpop/rpop <key>
例子:
sh127.0.0.1:6379> lpop list "two" 127.0.0.1:6379> rpop list "right" 127.0.0.1:6379> lrange list 0 -1 1) "one"
rpoplpush <key1> <key2>
指令列表右边吐出一个值,插到列表左边,其中 key1 是 rpop 的 key,key2 是 lpush 的 keyshrpoplpush <key1> <key2>
例子:
sh127.0.0.1:6379> rpush mylist "hello" (integer) 1 127.0.0.1:6379> rpush mylist "foo" (integer) 2 127.0.0.1:6379> rpush mylist "bar" (integer) 3 127.0.0.1:6379> rpoplpush mylist myotherlist "bar" 127.0.0.1:6379> lrange mylist 0 -1 1) "hello" 2) "foo" 127.0.0.1:6379> lrange myotherlist 0 -1 1) "bar"
llen <key>
指令获得列表长度shllen <key>
例子:
sh127.0.0.1:6379> flushdb OK 127.0.0.1:6379> lpush list "one" (integer) 1 127.0.0.1:6379> lpush list "two" (integer) 2 127.0.0.1:6379> lpush list "three" (integer) 3 127.0.0.1:6379> llen list # 返回列表的长度 (integer) 3
linsert <key> before/after <value> <newValue>
指令在元素某个值的前面 / 后面插入新值,如果 value 有多个,则插入最前面的那个shlinsert <key> before/after <value> <newValue>
例子:
sh127.0.0.1:6379> rpush mylist "Hello" (integer) 1 127.0.0.1:6379> rpush mylist "world" (integer) 2 127.0.0.1:6379> lrange mylist 0 -1 1) "Hello" 2) "world" 127.0.0.1:6379> linsert mylist BEFORE "world" "There" (integer) 3 127.0.0.1:6379> lrange mylist 0 -1 1) "Hello" 2) "There" 3) "world"
lrem <key> <n> <value>
指令从左边删除 n 个 value(从左到右),如果有多个一样的 lement,则删除列表最前面的shlrem <key> <n> <value>
例子:
sh127.0.0.1:6379> lrem list 1 "two" (integer) 1 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "one"
lset <key> <index> <value>
指令将列表 key 下标为 index 的值替换成 valueshlset <key> <index> <value>
例子:
sh127.0.0.1:6379> exists list # 对空列表(key 不存在)进行 LSET (integer) 0 127.0.0.1:6379> lset list 0 item # 报错 (error) ERR no such key 127.0.0.1:6379> lpush list "value1" # 对非空列表进行 LSET (integer) 1 127.0.0.1:6379> lrange list 0 0 1) "value1" 127.0.0.1:6379> lset list 0 "new" # 更新值 OK 127.0.0.1:6379> lrange list 0 0 1) "new" 127.0.0.1:6379> lset list 1 "new" # index 超出范围报错 (error) ERR index out of range
ltrim key
指令对一个列表进行修剪(trim),只保留指定列表中区间内的元素,不在指定区间之内的元素都将被删除bash127.0.0.1:6379> rpush mylist "hello" "hello" "hello2" "hello3" (integer) 4 127.0.0.1:6379> ltrim mylist 1 2 OK 127.0.0.1:6379> lrange mylist 0 -1 1) "hello" 2) "hello2"
List 的数据结构为快速链表 quickList
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next。
Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
集合Set
集合 Set 特点:无序,不重复。底层其实是一个 value 为 null 的 hash 表,所以添加,删除,查找的复杂度都是 O(1)
sadd <key> <value1> <value2> ...
指令将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略shsadd <key> <value1> <value2> ...
例子:
shsadd k1 v1 v2 v3
smembers <key>
指令取出该集合的所有值shsmembers <key>
sismember <key> <value>
指令判断集合是否为含有该值,有 1,没有 0shsismember <key> <value>
案例:
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "kele"
(integer) 1
127.0.0.1:6379> sadd myset "kele" # 重复值不插入 返回 0
(integer) 0
127.0.0.1:6379> smembers myset # 查看集合中所有成员
1) "kele"
2) "hello"
127.0.0.1:6379> sismember myset "hello" # 是否是此集合的成员 是 1
(integer) 1
127.0.0.1:6379> sismember myset "world"
(integer) 0
scard <key>
指令返回该集合的元素个数shscard <key>
例子:
sh127.0.0.1:6379> scard myset (integer) 2
srem <key> <value1> <value2> ...
指令删除集合中的某个元素shsrem <key> <value1> <value2> ...
例子:
sh127.0.0.1:6379> srem myset "kele" (integer) 1 127.0.0.1:6379> smembers myset 1) "hello"
spop <key>
指令随机从该集合中吐出一个值,key 里就没有该值了shspop <key>
例子:
sh127.0.0.1:6379> smembers myset 1) "kele" 2) "world" 3) "hello" 127.0.0.1:6379> spop myset "world" 127.0.0.1:6379> spop myset 2 1) "kele" 2) "hello"
srandmember <key> <n>
指令随机从该集合中取出 n 个值。不会从集合中删除shsrandmember <key> <n>
例子:
sh127.0.0.1:6379> smembers myset 1) "kele" 2) "world" 3) "hello" 127.0.0.1:6379> srandmember myset "hello" 127.0.0.1:6379> srandmember myset 2 1) "world" 2) "kele" 127.0.0.1:6379> srandmember myset 2 1) "kele" 2) "hello"
smove <key1> <key2> <value>
指令把集合中一个值从一个集合移动到另一个集合,其中 key1 为要获取的集合,key2 为放入的集合shsmove <key1> <key2> <value>
例子:
sh127.0.0.1:6379> sadd myset "hello" # myset 添加元素 (integer) 1 127.0.0.1:6379> sadd myset "world" (integer) 1 127.0.0.1:6379> sadd myset "kele" (integer) 1 127.0.0.1:6379> sadd myset2 "set2" # myset2 添加元素 (integer) 1 127.0.0.1:6379> smove myset myset2 "kele" (integer) 1 127.0.0.1:6379> smembers myset 1) "world" 2) "hello" 127.0.0.1:6379> smembers myset2 1) "kele" 2) "set2"
sinter <key1> <key2>
指令返回两个集合的交集元素shsinter <key1> <key2>
sunion <key1> <key2>
指令返回两个集合的并集元素shsunion <key1> <key2>
sdiff <key1> <key2>
指令返回两个集合的差集元素(key1 中的,不包含 key2 中的)shsdiff <key1> <key2>
案例:
127.0.0.1:6379> sadd key1 "a" # key1
(integer) 1
127.0.0.1:6379> sadd key1 "b"
(integer) 1
127.0.0.1:6379> sadd key1 "c"
(integer) 1
127.0.0.1:6379> sadd key2 "c" # key2
(integer) 1
127.0.0.1:6379> sadd key2 "d"
(integer) 1
127.0.0.1:6379> sadd key2 "e"
(integer) 1
127.0.0.1:6379> sdiff key1 key2 # 差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2 # 交集
1) "c"
127.0.0.1:6379> sunion key1 key2 # 并集
1) "a"
2) "b"
3) "c"
4) "e"
5) "d"
在微博中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis 还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
哈希Hash
特点:键值对集合,也是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
类似与 Java 的 Map<String, Map<Object,Object>>
,即双 Map。
通过 key(用户 ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
hset <key> <field1> <value> <field2> <value> ...
指令给集合 key 的 filed 键赋值 value,批量也可以,4.0 之前是 hmset,现在 hset 也可以批量添加shhset <key> <field1> <value> <field2> <value> ...
例子:
shhset user:1000 name kele age 18 gender boy
hget <key> <field>
指令从 key 集合取出 valueshhget <key> <field>
例子:
shhget user:1000 name
hexists <key> <field>
指令查看哈希表 key 中,给定域 field 是否存在shhexists <key> <field>
例子:
sh127.0.0.1:6379> hexists myhash field1 (integer) 1 127.0.0.1:6379> hexists myhash field3 (integer) 0
hkeys <key>
指令列出该 hash 集合的所有 fieldshhkeys <key>
hvals <key>
指令列出该 hash 集合的所有 valueshhvals <key>
例子:
sh127.0.0.1:6379> hkeys myhash 1) "field2" 2) "field1" 127.0.0.1:6379> hvals myhash 1) "World" 2) "Hello"
hincrby <key> <field> <increment>
指令为哈希表 key 中的域 field 的值加上增量shhincrby <key> <field> <increment>
例子:
sh127.0.0.1:6379> hset myhash field 5 (integer) 1 127.0.0.1:6379> hincrby myhash field 1 (integer) 6 127.0.0.1:6379> hincrby myhash field -1 (integer) 5 127.0.0.1:6379> hincrby myhash field -10 (integer) -5
hsetnx <key> <filed> <value>
指令将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在shhsetnx <key> <filed> <value>
例子:
sh127.0.0.1:6379> hsetnx myhash field1 "hello" (integer) 1 # 设置成功,返回 1 。 127.0.0.1:6379> hsetnx myhash field1 "world" (integer) 0 # 如果给定字段已经存在,返回 0 127.0.0.1:6379> hget myhash field1 "hello"
有序集合Zset
有序集合 zset 与普通集合 set 非常相似,是一个没有重复元素的字符串集合。
不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复。
zadd <key> <score1> <value1> <score2> <value2> ...
指令将一个或多个 member 元素及其 score 值加入到有序集 key 当中shzadd <key> <score1> <value1> <score2> <value2> ...
例如:
shzadd topn 1000 java 800 c++ 600 php 400 js
zrange <key> <start> <stop> [withscores]
指令返回有序集 key 中,下标在 start 和 stop 之间的元素带 WITHSCORES,可以让分数一起和值返回到结果集
shzrange <key> <start> <stop> [withscores]
例如:(0 和 -1 代表查询所有)
sh127.0.0.1:6379> zrange topn 0 -1 withscores 1) "java" 1000 2) "c++" 800 3) "php" 600 4) "js" 400
zrevrange <key> <start> <stop> [withscores]
指令同上,改为从大到小排列```sh zrevrange <key> <start> <stop> [withscores] ```
zrangebyscore <key> <min> <max> [withscores] [limit offset count]
指令返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max)的成员。 有序集成员按 score 值递增(从小到大)次序排列shzrangebyscore <key> <min> <max> [withscores] [limit offset count]
zrevrangebyscore <key> <min> <max> [withscores] [limit offset count]
指令同上,改为从大到小排列```sh zrevrangebyscore <key> <min> <max> [withscores] [limit offset count] ```
例子:
sh127.0.0.1:6379> zadd salary 2500 xiaoming (integer) 1 127.0.0.1:6379> zadd salary 5000 xiaohong (integer) 1 127.0.0.1:6379> zadd salary 500 kele (integer) 1 # Inf 无穷大量 +∞,同样地,-∞ 可以表示为 -Inf。 127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示整个有序集 1) "kele" 2) "xiaoming" 3) "xiaohong" 127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 递增排列 1) "kele" 2) "500" 3) "xiaoming" 4) "2500" 5) "xiaohong" 6) "5000" 127.0.0.1:6379> zrevrange salary 0 -1 withscores # 递减排列 1) "xiaohong" 2) "5000" 3) "xiaoming" 4) "2500" 5) "kele" 6) "500" # 显示工资 <= 2500 的所有成员 127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores 1) "kele" 2) "500" 3) "xiaoming" 4) "2500"
zincrby <key> <increment> <value>
指令为元素的 score 加上增量shzincrby <key> <increment> <value>
zrem <key> <value>
指令删除该集合下,指定值的元素shzrem <key> <value>
例子:
sh127.0.0.1:6379> zrange salary 0 -1 1) "kele" 2) "xiaoming" 3) "xiaohong" 127.0.0.1:6379> zrem salary kele (integer) 1 127.0.0.1:6379> zrange salary 0 -1 1) "xiaoming" 2) "xiaohong"
zcount <key> <min> <max>
指令统计该集合,分数区间内的元素个数shzcount <key> <min> <max>
例子:
sh127.0.0.1:6379> zadd myset 1 "hello" (integer) 1 127.0.0.1:6379> zadd myset 2 "world" 3 "kele" (integer) 2 127.0.0.1:6379> zcount myset 1 3 (integer) 3 127.0.0.1:6379> zcount myset 1 2 (integer) 2
zrank <key> <value>
指令返回该值在集合中的排名,从 0 开始shzrank <key> <value>
例子:
sh127.0.0.1:6379> zadd salary 2500 xiaoming (integer) 1 127.0.0.1:6379> zadd salary 5000 xiaohong (integer) 1 127.0.0.1:6379> zadd salary 500 kele (integer) 1 127.0.0.1:6379> zrange salary 0 -1 withscores # 显示所有成员及其 score 值 1) "kele" 2) "500" 3) "xiaoming" 4) "2500" 5) "xiaohong" 6) "5000" 127.0.0.1:6379> zrank salary kele # 显示 kele 的薪水排名,最少 (integer) 0 127.0.0.1:6379> zrank salary kele # 显示 xiaohong 的薪水排名,第三 (integer) 2
zrevrank <key> <value>
指令返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序shzrevrank <key> <value>
例子:
sh127.0.0.1:6379> zrevrank salary kele (integer) 2 127.0.0.1:6379> zrevrank salary kele (integer) 0
案例:利用 zset 实现一个文章访问量的排行榜
zadd topn 1000 java 800 c++ 600 php 400 js # 添加文章以及评分
zrevrange topn 0 9 withscores # 评分从大到小查询
SortedSet(zset)是 Redis 提供的一个非常特别的数据结构,一方面它等价于 Java 的数据结构 Map,可以给每一个元素 value 赋予一个权重 score,另 一方面它又类似于 TreeSet,内部的元素会按照权重 score 进行排序,可以得到每个元素的名次,还可以通过 score 的范围来获取元素的列表。
zset 底层使用了两个数据结构:
hash,hash 的作用就是关联元素 value 和权重 score,保障元素 value 的唯一性,可以通过元素 value 找到相应的 score 值。
跳跃表,跳跃表的目的在于给元素 value 排序,根据 score 的范围获取元素列表。
指令总结
虽然看了五个数据类型的 API 和例子,但是两者混为一起,难免心生抵触,不想看例子,这里以表格形式总结 API,不参杂任何例子。
键(key)命令
指令 | 含义 |
---|---|
dbsize | 查看当前数据库的 key 的数量 |
keys * | 指令查看当前库所有 key |
exists key | 指令判断某个 key 是否存在 |
type key | 指令查看 key 的类型是哪个 |
del key | 指令删除指定的 key |
unlink key | 指令根据 value 选择非阻塞删除(先将 keys 从 keysapce 元数据中删除,真正的删除会在后续异步操作) |
expire key time | 指令给指定的 key 设置过期时间(time 以秒为单位),当 key 过期时(生存时间为 0 ),它会被自动删除 |
ttl key | 指令查看 key 还有多少秒过期,-1 表示永不过期,-2 表示已过期 |
select num | 指令选择数据库,num 代表从 0-16,默认是 0 |
flushdb | 清空当前库 |
flushall | 清空所有库 |
字符串String
指令 | 含义 |
---|---|
set <key> <value> | 添加键值对,如果 key 已经存在则覆盖 value |
get <key> | 查看对应键值 |
append <key> <value> | 追加到原值的末尾 |
strlen <key> | 获得值的长度 |
setnx <key> <value> | 只有 key 不存在时,才加入该 key 的值 |
incr <key> | 将 key 中储存的数字值增 1,只能对数字值操作,如果为空,新增值为 1 |
decr <key> | 将 key 中储存的数字值减 1,只能对数字值操作,如果为空,新增值为 -1 |
incrby / decrby <步长> | 将 key 中储存的数字值增减。自定义步长 |
mset <key1> <value> <key2> <value2> ...... | 设置一个或者多个 key-value 键值对 |
mget <key1> <key2> ...... | 获取一个或者多个 key-value 键值对 |
msetnx <key1> <value> <key2> <value2> ...... | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 |
getrange <key> <起始位置> <结束位置> | 获得值的范围,类似 java 中的 substring |
getrange <key> <起始位置> <value> | 用 value 覆写所储存的字符串值,从 <起始位置> 开始(索引从 0 开始) |
setrange <key> <位置> <newValue> | 设置指定区间范围内的值 |
setex <key> <过期时间/秒> <value> | 设置键值的同时,设置过期时间,单位秒 |
psetex <key> <过期时间/毫秒> <value> | 设置键值的同时,设置过期时间,单位毫秒 |
getset <key> <value> | 以新换旧,设置了新值同时获得旧值 |
set user:1 value(json数据) | 存储对象 |
列表List
指令 | 含义 |
---|---|
lpush/rpush <key> <value1> <value2> <value3> ... | 从左边/右边插入一个或多个值,左右也就是首尾 |
lrange <key> <start> <stop> | 按照索引下标获得元素(从左到右,先进后出) |
lrange <key> 0 -1 | 如果 start 是 0,stop 是 -1,代表获取所有元素 |
lindex <key> <index> | 按照索引下标获得元素(从左到右)(-1 代表最后一个,0 代表是第一个) |
lpop/rpop <key> | 从左边/右边吐出一个值。吐出后该值就不存在 key 中 |
rpoplpush <key1> <key2> | 列表右边吐出一个值,插到列表左边,其中 key1 是 rpop 的 key,key2 是 lpush 的 key |
llen <key> | 获得列表长度 |
linsert <key> before/after <value> <newValue> | 在元素某个值的前面/后面插入新值,如果 value 有多个,则插入最前面的那个 |
lrem <key> <n> <value> | 从左边删除 n 个 value(从左到右),如果有多个一样的 lement,则删除列表最前面的的 |
lset <key> <index> <value> | 将列表 key 下标为 index 的值替换成 value |
ltrim key | 对一个列表进行修剪(trim),只保留指定列表中区间内的元素,不在指定区间之内的元素都将被删除 |
集合Set
指令 | 含义 |
---|---|
sadd <key> <value1> <value2> ... | 将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略 |
smembers <key> | 取出该集合的所有值 |
sismember <key> <value> | 判断集合是否为含有该值,有 1,没有 0 |
scard <key> | 返回该集合的元素个数 |
srem <key> <value1> <value2> ... | 删除集合中的某个元素 |
spop <key> | 随机从该集合中吐出一个值,key 里就没有该值了 |
srandmember <key> <n> | 随机从该集合中取出 n 个值。不会从集合中删除 |
smove <key1> <key2> <value> | 把集合中一个值从一个集合移动到另一个集合,其中 key1 为要获取的集合,key2 为放入的集合 |
sinter <key1> <key2> | 返回两个集合的交集元素 |
sunion <key1> <key2> | 返回两个集合的并集元素 |
sdiff <key1> <key2> | 返回两个集合的差集元素(key1 中的,不包含 key2 中的) |
哈希Hash
指令 | 含义 |
---|---|
hset <key> <field1> <value> <field2> <value> ... | 给集合 key 的 filed 键赋值 value,批量也可以,4.0 之前是 hmset,现在 hset 也可以批量添加 |
hget <key> <field> | 从 key 集合取出 value |
hexists <key> <field> | 查看哈希表 key 中,给定域 field 是否存在 |
hkeys <key> | 列出该 hash 集合的所有 field |
hvals <key> | 列出该 hash 集合的所有 value |
hincrby <key> <field> <increment> | 为哈希表 key 中的域 field 的值加上增量 |
hsetnx <key> <filed> <value> | 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 |
有序集合Zset
指令 | 含义 |
---|---|
zadd <key> <score1> <value1> <score2> <value2> ... | 将一个或多个 member 元素及其 score 值加入到有序集 key 当中 |
zrange <key> <start> <stop> [withscores] | 返回有序集 key 中,下标在 star t和 stop 之间的元素,带 WITHSCORES,可以让分数一起和值(从小到大)返回到结果集 |
zrevrange <key> <start> <stop> [withscores] | 同上,改为从大到小排列 |
zrangebyscore <key> <min> <max> [withscores] [limit offset count] | 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。 有序集成员按 score 值递增(从小到大)次序排列 |
zrevrangebyscore <key> <min> <max> [withscores] [limit offset count] | 同上,改为从大到小排列 |
zincrby <key> <increment> <value> | 为元素的 score 加上增量 |
zrem <key> <value> | 删除该集合下,指定值的元素 |
zcount <key> <min> <max> | 统计该集合,分数区间内的元素个数 |
zrank <key> <value> | 返回该值在集合中的排名,从 0 开始 |
zrevrank <key> <value> | 返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序 |