第一章 基本数据类型-API的理解和使用
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
Redis 支持对键添加过期时间,当超过过期时间后,会自动删除键;
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 种
- int : 8 个字节的长整型
- enbstr :小于等于 39 个字节的字符串
- 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 内部编码
**ziplist (压缩列表)
第一章 基本数据类型-API的理解和使用相关推荐
- [k8s] 第一章 十分钟带你理解Kubernetes核心概念
本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念.组件和工作原理. 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署 ...
- csapp第一章 计算机系统漫游 学习和理解
计算机系统是由硬件和系统软件组成的. 系统的具体实现在变,但系统内在的概念没有变. 所有的系统都有相似的硬件,相似的软件组件,它们执行着相似的功能. 这些组件是如何工作的?这些组件是如何影响程序的正确 ...
- .NET Core IdentityServer4实战 第一章-入门与API添加客户端凭据
内容:本文带大家使用IdentityServer4进行对API授权保护的基本策略 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 本文将要讲述如何使用IdentityServer4 ...
- c语言写报告抽象数据类型,数据结构(C语言版)第一章 抽象数据类型的表示与实现...
//文件名:Triplet.c //因为C语言没有引用,所以用指针代替引用 //函数的头文件 #include #include //函数结果状态码 #define TRUE 1 #define FA ...
- 第一章 C数据类型及语句
1.我的第一个c语言程序 #intclude<stdio.h> //头文件 int main()//main:主函数,任意一个c语言程序中必须有且只有一个主函数,是程序的入口函数 { pr ...
- python数据结构与算法 (翻译)第一章
第一章 抽象数据类型 算法的学习是计算机科学的基础.算法是为了在有限的时间内解决问题,而做出的一系列清晰和精确的逐步说明.算法通过将逐步指令转换成可由计算机执行的计算机程序来实现.这个翻译过程被称为计 ...
- 流畅的python读书笔记-第一章Python 数据模型
第一章 python数据类型 1 隐式方法 利用collections.namedtuple 快速生成类 import collectionsCard = collections.namedtuple ...
- 《破解数字VLSI验证面试》翻译计划——第一章
前言 本文基于<破解数字VLSI验证面试>翻译计划--综述展开翻译的! 第一章:数字逻辑设计 理解数字逻辑设计的基本原理是执行VLSI行业任何工作的基本技能.因此,无论面试是针对ASIC设 ...
- C++ API 设计 06 第一章 简介
第一章 简介 1.1 应用程序编程接口是什么? 应用程序编程接口(API)提供对问题的一个抽象,并说明客户端如何与实现这个问题的解决方案的软件组件来进行交互. 这些组件本身通常作为一个软件库发布,允许 ...
最新文章
- swift 中showAlertTitle的使用
- 科大星云诗社动态20210910
- 【转】ABP源码分析三十九:ABP.Hangfire
- java.lang.UnsatisfiedLinkError: D:\Program Files\apache-tomcat-9.0.30\bin
- java输出华氏摄氏温度转换表_Python练习题2.10输出华氏-摄氏温度转换表
- “别了,小黄文” 微信打击低俗小说:2019年处理违规账号6.6万+
- localStorage存储数组以及取数组方法。
- JVM 新生代老年代
- MVC架构下,使用NPOI读取.DOCX文档中表格的内容
- java规则引擎Drools实战
- 【抖音视频去水印小程序开源】mosousuo—微信小程序下载抖音去水印视频
- signature=99d87437cab1487c89a59a65cc379430,剖析根据汉字转拼音的JQuery插件源码
- 计算机专业学习自然辩证法,深度学习 自然辩证法
- 2018-8-10-win10-uwp-如何开始写-uwp-程序
- IIS反向代理 URL重写 404或500 错误问题的解决方案
- 韩国为什么“恢复”汉字?
- 数据挖据---机器学习平台之H2O架构/接口/实践
- 你还记得当年高考时的样子吗?
- C++进阶——STL源码之红黑树(_Rb_tree)
- linux下 软件安装与卸载(3)
热门文章
- 解决java报错class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.Comparable
- 常青藤爸爸《唱诵国学经典系列活动》在首都图书馆圆满举行
- 十五天掌握OpenCV——图像上的算术运算
- HTML5简明教程系列之HTML5基础(一)
- 高德地图精确定位和获取地理位置
- 计算机视觉实战的深度学习实战二:图像预处理
- iframe标签全屏
- 【读书笔记】《大型互联网企业安全架构(石祖文)》
- 【前辈经验】——前端职位描述
- Mac 更新系统后无法正常启动
- [k8s] 第一章 十分钟带你理解Kubernetes核心概念