1.1 基础

1.1.1 全局命令

​ Redis有五种数据结构,对于键来说有一些通用的命令

1、查看所有的键

​ **Keys **

127.0.0.1:6379> set name_1 kebe
OK
127.0.0.1:6379> set name_2 james
OK
127.0.0.1:6379> set name_3 wade
OK
127.0.0.1:6379> keys *
1) "name_3"
2) "name_1"
3) "name_2"
127.0.0.1:6379>

2、键总数

dbsize

127.0.0.1:6379> dbsize
(integer) 3
127.0.0.1:6379>

3、检查键是否存在

exists key 如果 key 存在返回 1,不存在返回 0;

127.0.0.1:6379> dbsize
(integer) 3
127.0.0.1:6379> exists name_1
(integer) 1
127.0.0.1:6379> exists key_4
(integer) 0
127.0.0.1:6379>

4、删除键

del key [key…] 无论是什么类型的数据格式,del命令都可以删除。删除成功返回 1,删除失败(不存在)返回 0;

127.0.0.1:6379> del name_1
(integer) 1
127.0.0.1:6379> del name_1
(integer) 0
127.0.0.1:6379> del name_2 name_3
(integer) 2
127.0.0.1:6379>

5、键过期

expire key seconds

  1. Redis 支持对键添加过期时间,当超过过期时间后,会自动删除键;

  2. ttl 命令会返回键的剩余过期时间,它有 3 中返回值:

    • 大于等于 0 的整数:剩余过期时间

    • -1:键没有设置过期时间

    • -2:键不存在

127.0.0.1:6379> set name_1 kebe
OK
127.0.0.1:6379> set name_2 james
OK
127.0.0.1:6379> ttl name_3
(integer) -2
127.0.0.1:6379> expire name_1 60
(integer) 1
127.0.0.1:6379> ttl name_1
(integer) 56
127.0.0.1:6379> ttl name_2
(integer) -1
127.0.0.1:6379>

6、键的数据类型

type key 如果 key 不存在,返回 none

127.0.0.1:6379> type name_2
string
127.0.0.1:6379> lpush list_1 a b c d e
(integer) 5
127.0.0.1:6379> type list_1
list
127.0.0.1:6379> type name_4
none
127.0.0.1:6379>

1.1.2 数据结构和内部编码

​ type 命令就是返回对应 key 的数据结构类型

  • string(字符串)
  • hash(哈希)
  • list(列表)
  • set(集合)
  • zset(有序集合)

以上这写都是Redis 对外的数据结构,实际Redis 还有自己的底层的内部编码,如下图

1.2 字符串(String)

1.2.1 常用命令

命令 描述 时间复杂度
set key value 添加 O(1)
get key 获取 O(1)
del key [key…] 删除/批量删除 O(n) n 键的长度
mset key value [key value…] 批量添加 O(n) n 键的长度
mget key [key…] 批量获取 O(n) n 键的长度
incr key 自增+1 O(1)
decr key 自减-1 O(1)
incrby key increment 增加指定长度 O(1)
decrby key decrement 减少指定长度 O(1)
incrbyfloat key increment 自增浮点数 O(1)
append key value 追加 O(1)
strlen key 字符串长度 O(1)
getset key value 设置并返回原值 O(1)
setrange key offset value 设置指定位置的字符 O(1)
getrange key start end 获取指定位置的字符 O(n),n 是字符串长度,由于获取字符串非常快,字符串长度不长可以视同为 O(1)
1、示例:
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set name_1 "Kebe Bryant"
OK
127.0.0.1:6379> get name_1
"Kebe Bryant"
127.0.0.1:6379> set name_2 james
OK
127.0.0.1:6379> del name_2
(integer) 1
127.0.0.1:6379> set name_2 james
OK
127.0.0.1:6379> mget name_1 name_2
1) "Kebe Bryant"
2) "james"
127.0.0.1:6379> mset name_3 wade name_4 irving
OK
127.0.0.1:6379> set name_5 1
OK
127.0.0.1:6379> incr name_5
(integer) 2
127.0.0.1:6379> get name_5
"2"
127.0.0.1:6379> decr name_5
(integer) 1
127.0.0.1:6379> get name_5
"1"
127.0.0.1:6379> incrby name_5 3
(integer) 4
127.0.0.1:6379> get name_5
"4"
127.0.0.1:6379> decrby name_5 3
(integer) 1
127.0.0.1:6379> get name_5
"1"
127.0.0.1:6379> incrbyfloat name 2.3
"2.3"
127.0.0.1:6379> incrbyfloat name_5 2.3
"3.3"
127.0.0.1:6379> get name_5
"3.3"
127.0.0.1:6379> append name_1 "no.24"
(integer) 16
127.0.0.1:6379> get name_1
"Kebe Bryantno.24"
127.0.0.1:6379> strlen name_1
(integer) 16
127.0.0.1:6379> getset name_1 kebe
"kebe"
127.0.0.1:6379> setrange name_1 0 K
(integer) 4
127.0.0.1:6379> getrange name_1 0 -1
"Kebe"
127.0.0.1:6379>

1.2.2 内部编码

1、字符串类型的内部编码有 3 种
  1. int : 8 个字节的长整型
  2. enbstr :小于等于 39 个字节的字符串
  3. raw : 大于 39 个字节的字符串

Redis 会根据当前值得类型和长度决定使用那种内部编码实现:

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set name_1 kebe
OK
127.0.0.1:6379> object encoding name_1
"embstr"
127.0.0.1:6379> set name_2 123
OK
127.0.0.1:6379> object encoding name_2
"int"
127.0.0.1:6379> set name_3 "The 3rd leading score in NBA history,18 time All-star,4 time All-star MVP,The 2008 MVP,2 time NBA finals MVP,5 time NBA champion,A 6`6 guard from Lower Merion High School,In his twenty season,The BLACK MAMBA,The one,The only,No._24,Kobe Bryant."
OK
127.0.0.1:6379> object encoding name_3
"raw"
127.0.0.1:6379>

1.2.3 经典场景

1、缓存功能

​ web 开发我们经常会以MySQL、Oracle作为数据存储,使用Redis作为缓存。80%的请求被打倒缓存中获取对应数据,由于Redis可以支撑高并发的特性,可以大大服务对数据库的压力;

1、图例:

2、代码设计 (java)
 /*** 根据用户编号获取用户信息* @param userId 用户编号* @return UserModel*/public UserModel getUserInfo(String userId){// system:user:info:2String userKey = "s:u:i:" + userId;// 获取用户String userModel = stringRedisTemplate.opsForValue().get(userKey);// 是否命中缓存if (StringUtils.isBlank(userModel)) {// 数据库获取用户信息UserModel userModelData = userMapper.selectUserInfoByUserId(userId);// 将获取的数据放入缓存stringRedisTemplate.opsForValue().setIfPresent(userKey,userModelData.toString(),30,TimeUnit.MINUTES);return  userModelData;}return JSONObject.parseObject(userModel,UserModel.class);}
2、计数

​ 简单的标志位,例如:统计今日系统访问量,用户登录次数,分布式主键主键等

1、代码设计(java)
   public void demo_1(){// 系统每日访问 system:browse:20210801String systemKey = "s:b:"+ LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);stringRedisTemplate.opsForValue().increment(systemKey);// 用户登录次数 user:login:20210801String loginKey = "u:l:"+ LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);stringRedisTemplate.opsForValue().increment(systemKey);// 分部式主键 dataBase:table:id;String idKey = "d:t:i";Long id = stringRedisTemplate.opsForValue().increment(idKey);}
3、共享session

多系统用户跳转的互相认证令牌,

1、图例

4、限速

​ 有时候为了限制不当操作,系统在对应的请求方法上,添加访问次数的拦截;

1、代码设计(java)
  /*** 用户编号获取是否通过方法* @param userId 用户* @return true-过 false-不过*/public Boolean getShotLimitStatus(String userId) {// 访问限制 short:limit:queryMoney:用户编号String limitKey = "s:l:qM:"+userId;// 1min 限制5次  set key value EX 60 NXstringRedisTemplate.opsForValue().setIfPresent(limitKey, "1", 1, TimeUnit.MINUTES);return stringRedisTemplate.opsForValue().increment(limitKey) < 6;}

1.3 哈希(Hash)

1.3.1 常用命令

命令 描述 时间复杂度
hset key field value 添加key 列名 O(1)
hget key field 获取key field O(1)
hdel key field [field…] 删除key field O(k) k是field的个数
hlen key 获取key 个数 O(1)
hgetall key 获取key 的 field 和 value O(n) n是field总数
hmget field [field . … ] 批量获取 O(k) k是field的个数
hmset field value [field value . . . ] 批量添加 O(k) k是field的个数
hexists key field 添加 key 的 field 是否存在 O(1)
hkeys key 获取 key 的所有列名 O(n) n是field总数
hvals key 获取 key 的所有value O(n) n是field总数
hsetnx key field value 添加 key field 的value 不存在成功,反之失败 O(1)
hincrby key field increment 和 string incrby一样 O(1)
hincrbyfloat key field increment 和 string incrbyfloat一样 O(1)
hstrlen key field 计算 Key 的 field 的长度 O(1)
1、示例:
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset user:1 id 1
(integer) 1
127.0.0.1:6379> hget user:1 id
"1"
127.0.0.1:6379> hset user:1 name kebe
(integer) 1
127.0.0.1:6379> hset user:1 sex 0
(integer) 1
127.0.0.1:6379> hdel user:1 id name
(integer) 2
127.0.0.1:6379> hlen user:1
(integer) 1
127.0.0.1:6379> hgetall user:1
1) "sex"
2) "0"
127.0.0.1:6379> hmget user:1 sex
1) "0"
127.0.0.1:6379> hmset user:1 name kebe id 1
OK
127.0.0.1:6379> hexists user:1 id
(integer) 1
127.0.0.1:6379> hkeys user:1
1) "sex"
2) "name"
3) "id"
127.0.0.1:6379> hvals user:1
1) "0"
2) "kebe"
3) "1"
127.0.0.1:6379> hsetnx user:1 id 2
(integer) 0
127.0.0.1:6379> hvals user:1
1) "0"
2) "kebe"
3) "1"
127.0.0.1:6379> hincrby user:1 id 2
(integer) 3
127.0.0.1:6379> hvals user:1
1) "0"
2) "kebe"
3) "3"
127.0.0.1:6379> hincrbyfloat user:1 id 2.3
"5.3"
127.0.0.1:6379> hvals user:1
1) "0"
2) "kebe"
3) "5.3"
127.0.0.1:6379> hstrlen user:1 id
(integer) 3
127.0.0.1:6379>

1.3.2 内部编码

1、ziplist (压缩列表):

​ 当哈希类型元素个数小于hash-max- ziplist-entries配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis 会使用ziplist作为哈希的内部实现,ziplist 使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。

2、hashtable (哈希表):

​ 当哈希类型无法满足ziplist的条件时,Redis 会使用hashtable作为哈希的内部实现,因此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为0(1)。

演示下哈希类型的内部编码及变化:

2.1、当 field 个数比较少且没有大的 value 时,内部编码是 ziplist
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hmset user:1 id 1 name kebe sex 0
OK
127.0.0.1:6379> object encoding user:1
"ziplist"
2.2、当有 value 大于 64 字节,内部编码会由 ziplist 变为 hashtable
127.0.0.1:6379> hset user:1 description "The 3rd leading score in NBA history,18 time All-star,4 time All-star MVP,The 2008 MVP,2 time NBA finals MVP,5 time NBA champion.A 6`6 guard from Lower Merion High School,In his twenty season"
(integer) 1
127.0.0.1:6379> object encoding user:1
"hashtable"
2.3、当 field 个数超过 512,内部编码也会由 ziplist 变为 hashtable

​ 这个留个你们去演示吧,

1.3.3 经典场景

​ 下图:

  • 左边 是关系型数据表存储、展示用户信息,列是用户属性,行是用户信息
  • 右边 是哈希类型存储,field 是用户属性,value 是用户信息

这个类型相较于String(字符串),缓存用户数据,哈希变的更直观,但是需要注意的是,如果实体中的属性是 null,那么 hash 中就不会存储对应的 field,还要注意 hash 在 ziplist 和 hashtable 两种内存编码的转换,hashtable 会消耗更多的内存

1、代码设计(java)
 /*** 根据用户编号获取用户信息* @param userId 用户编号* @return UserModel*/public UserModel getUserInfo(String userId){// system:user:info:2 为了减少由于键过长造成内存的浪费,建议选择String userKey = "s:u:i:"+userId;// 获取用户Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(userKey);// 是否命中缓存if (entries.isEmpty()) {// 数据库获取用户信息UserModel userModel = userMapper.selectUserInfoByUserId(userId);// 将获取的数据放入缓存stringRedisTemplate.opsForHash().putAll(userKey, JSON.parseObject(JSON.toJSONString(userModel), Map.class));// 过期时间 24hstringRedisTemplate.expire(userKey,24, TimeUnit.HOURS);return userModel;}return JSON.parseObject(JSON.toJSONString(entries), UserModel.class);}

1.4 列表(List)

1.4.1 常用命令

命令 描述 时间复杂度
rpush key value [value … . ] 添加(右端进入) O(k),k是元素个数
lpush key value [value …] 添加(左端进入) O(k),k是元素个数
linsert key beforelafter pivot value 从某个指定元素的前/后添加 O(n),n是pivot距离列表头或尾的距离
lrange key start end 获取指定范围内的元素列表 O(s+n),s是start偏移量,n是start到end的范围
lindex key index 获取指定索引下标的元素 O(n),n是索引的偏移量
llen key 获取列表长度 O(1)
lpop key 从列表左端弹出元素 O(1)
rpop key 从列表右端弹出元素 O(1)
lrem count value 删除指定元素 O(n),n是列表长度
ltrim key start end 根据索引范截取列表 O(n),n是要裁剪的元素总数
lset key index value 修改指定索引下标的元素 O(n),n是索引的偏移量
blpop brpop 阻塞操作 O(1)
1、示例
127.0.0.1:6379> lpush user:1 kebe
(integer) 1
127.0.0.1:6379> rpush user:1 james wade
(integer) 3
127.0.0.1:6379> linsert user:1 before james paul
(integer) 4
127.0.0.1:6379> lrange user:1 0 -1
1) "kebe"
2) "paul"
3) "james"
4) "wade"
127.0.0.1:6379> lindex user:1 1
"paul"
127.0.0.1:6379> llen user:1
(integer) 4
127.0.0.1:6379> lpop user:1
"kebe"
127.0.0.1:6379> rpop user:1
"wade"
127.0.0.1:6379> lrange user:1 0 -1
1) "paul"
2) "james"
127.0.0.1:6379> lrange user:1 0 -1
1) "paul"
2) "james"
127.0.0.1:6379> lrem user:1 1 paul
(integer) 1
127.0.0.1:6379> lpush user:1 kebe paul wade
(integer) 4
127.0.0.1:6379> ltrim user:1 0 1
OK
127.0.0.1:6379> lset user:1 0 love
OK
127.0.0.1:6379> lrange user:1 0 -1
1) "love"
2) "paul"

1.4.2 内部编码

1、列表类型的内部编码有两种。
  • ziplist (压缩列表):当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时(默认64字节),Redis 会选用ziplist来作为列表的内部实现来减少内存的使用。

  • linkedlist (链表):当列表类型无法满足ziplist的条件时,Redis 会使用因为列Iinkedlist作为列表的内部实现。

    Redis3.2后quicklist内部编码,简单地说它是以一个ziplist为节点的Iinkedlist,它结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,

1.4.3 经典场景

1、消息队列

​ Redis 的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插人元素,多个消费者客户端使用brpop命令阻塞式的“抢”尾部的元素,多个客户端保证了消费的负载均衡和高可用性。

2、文档列表

​ 全个周户有于自己的文事列来,观需建分页原示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素:

1、使用哈希(Hash)保存文章信息:

hmset acticle:1 title "活着" author "余华" createTime "1983年"
hmset acticle:2 title "平凡的世界" author "路遥" createTime "1986年"
hmset acticle:3 title "边城" author "沈从文" createTime "1934年"
hmset acticle:4 title "白鹿原" author "陈忠实" createTime "1993年"

2、使用列表(list)保存用户与文章信息:

lpush user:1 acticle:1 acticle:3
lpush user:2 acticle:2 acticle:4

3、列表获取用户和文章列表

acticles = lrange user:1 0 2
for (acticle in acticles){hgetall acticle
}

​ 使用列表类型保存和获取文章列表会存在两个问题。第一,如果每次 分页获取的文章个数较多,需要执行多次hgetall操作,此时可以考虑使用Pipeine (第3章会介绍)批量获取,或者考虑将文章数据序列化为字符串类型,使用mget批量获取。第二,分页获取文章列表时,lrange 命令在列表两端性能较好,但是如果列表较大,获取列表中间范围的元紫性能会变差,此时可以考虑将列表做二级拆分,或者使用Redis 3.2的quicklist内部编码实现,它结合ziplist和linkedlist的特点,获取列表中间范围的元素时也可以高效完成。

1.5 集合(Set)

1.5.1 常用命令

命令 描述 时间复杂度
sadd key element [element …] 添加元素 O(k),k是元素个数
srem key element [element …] 删除元素 O(k),k是元素个数
scard key 计算 key 元素个数 O(1)
sismember key element 判断元素是否在集合中 O(1)
srandmember key [count] 随机从集合返回指定个数元素 O(count)
spop key 从集合随机弹出元素 O(1)
smembers key 获取所有元素 O(n),n是元素总数
sinter key [key …] 或 sinterstore 多个集合的交集 O(m*k),k是多个集合中元素最少的个数、m是键个数
sunion key [key …] 或 suionstore 多个集合的并集 O(k),k是多个集合元素个数和
sdiff key [key …] 或 sdiffstore 多个集合的差集 O(k),k是多个集合元素个数和
1、示例
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd user:1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> srem user:1 1 2
(integer) 2
127.0.0.1:6379> scard user:1
(integer) 3
127.0.0.1:6379> sismember user:1 4
(integer) 1
127.0.0.1:6379> srandmember user:1
"5"
127.0.0.1:6379> spop user:1
"4"
127.0.0.1:6379> sadd user:2 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd user:3 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sinter user:1 user:2
1) "3"
2) "5"
127.0.0.1:6379> sinter user:2 user:3
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> sunion user:1 user:2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> sinter user:1 user:2
1) "3"
2) "5"
127.0.0.1:6379> sadd user 6 7
(integer) 2
127.0.0.1:6379> sdiff user:1 user
1) "3"
2) "5"

1.5.2 内部编码

  • intset (整数集合):当集合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认512个)时,Redis 会选用intset来作为集合的内部实现,从而减少内存的使用。

  • hashtable (哈希表):当集合类型无法满足intset的条件时,Redis 会使用hashtable作为集合的内部实现。

1、示例
127.0.0.1:6379> object encoding user
"intset"
127.0.0.1:6379> sadd user:3 kebe
(integer) 1
127.0.0.1:6379> object encoding user:3
"hashtable"

1.5.3 经典场景

​ 集合类型比较典型的使用场景是标签( tag)。例如一一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。例如一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为网站带来更多的利益。

1.6 有序集合(Zset)

1.6.1 常用命令

命令 描述 时间复杂度
zadd key score member [score member …] 添加一个或多个元素 O(kX log())k是添加成员的个数,n是当前有限集合成员个数
zcard key 获取集合的成员数 0(1)
zscore key member 获取key 指定元素的分数 0(1)
zrank key member
zrevrank key member
排名 O(log(n),n是当前有序集合成员个数
zrem key member [member . . .] 基础集合中的成员 O(k*log(n)),k 是删除成员的个数,n是当前有序合成员个数
zincrby key increment member 对应key 成员加分 O(log(n)),n是当前有序集合成员个数
zrange key start end [withscores]
zrevrange key start end [withscores]
排名 O(log(n)+k),k是要获取的成员个数,n是当前有序合成员个数
zrangebyscore key min max [withscores]
zrevrangebyscore key max min [withscores]
排名带分数 O(log(n)+k),k是要获取的成员个数,n是当前有序合成员个数
zcount key 返回集合成员 O(log(n)),n是当前有序集合成员个数
zremrangebyrank key start end 根据排名删除元素 O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
zremrangebyscore key min max 根据分数删除元素 O(log(n) +k), k是要删除的成员个数,n是当前有序集合成员个数
zinterstore destination numkeys key [key … O(n×k)+O(m×log(m),n是成员数最小的有序集合成员个数,k是有序集合的个数,m是结果集中成员个数
zinterstore destination numkeys key [key …] 交集 O(m)+O(m*log(m),n是所有有序集合成员个数和,m是结果集中成员个数
1、示例
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd user 1 kebe 2 james 3 wade
(integer) 3
127.0.0.1:6379> zcard user
(integer) 3
127.0.0.1:6379> score user kebe
(error) ERR unknown command 'score'
127.0.0.1:6379> zscore user kebe
"1"
127.0.0.1:6379> zrange user 0 3 withscores
1) "kebe"
2) "1"
3) "james"
4) "2"
5) "wade"
6) "3"
127.0.0.1:6379> zrevrank user kebe
(integer) 2
127.0.0.1:6379> zrevrank user james
(integer) 1
127.0.0.1:6379> zrevrank user wade
(integer) 0
127.0.0.1:6379> zrem user wade
(integer) 1
127.0.0.1:6379> zrange user 0 3 withscores
1) "kebe"
2) "1"
3) "james"
4) "2"
127.0.0.1:6379> zincrby user 1 kebe
"2"
127.0.0.1:6379> zrange user 0 3 withscores
1) "james"
2) "2"
3) "kebe"
4) "2"
127.0.0.1:6379> zrevrange user 0 3 withscores
1) "kebe"
2) "2"
3) "james"
4) "2"
127.0.0.1:6379> zincrby user 2 kebe
"4"
127.0.0.1:6379> zrangebyscore user 0 5 withscores
1) "james"
2) "2"
3) "kebe"
4) "4"
127.0.0.1:6379> zrevrangebyscore user 5 0 withscores
1) "kebe"
2) "4"
3) "james"
4) "2"
127.0.0.1:6379> zadd user 1 wade
(integer) 1
127.0.0.1:6379> zadd user 5 paul
(integer) 1
127.0.0.1:6379> zadd user 6 love
(integer) 1
127.0.0.1:6379> zremrangebyrank user 0 1
(integer) 2
127.0.0.1:6379> zrangebyscore user 0 10 withscores
1) "kebe"
2) "4"
3) "paul"
4) "5"
5) "love"
6) "6"
127.0.0.1:6379> zremrangebyscore user 0 4
(integer) 1
127.0.0.1:6379> zrangebyscore user 0 10 withscores
1) "paul"
2) "5"
3) "love"
4) "6"
127.0.0.1:6379> sadd score 1 kebe 2 james
(integer) 4
127.0.0.1:6379> zinterstore user:score 2 user score
(integer) 0
127.0.0.1:6379> sadd score 1 paul
(integer) 1
127.0.0.1:6379> zinterstore user:score 2 user score
(integer) 1
127.0.0.1:6379> zrange user:score 0 -1 withscores
1) "paul"
2) "6"
127.0.0.1:6379>

1.6.2 内部编码