第一章 基本数据类型-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

  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自增+1O(1)
decr key自减-1O(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:2
        String 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:20210801
        String systemKey = "s:b:"+ LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
        stringRedisTemplate.opsForValue().increment(systemKey);
        // 用户登录次数 user:login:20210801
        String 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 NX
        stringRedisTemplate.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 fieldO(1)
hdel key field [field…]删除key fieldO(k) k是field的个数
hlen key获取key 个数O(1)
hgetall key获取key 的 field 和 valueO(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 的所有valueO(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));
            // 过期时间 24h
            stringRedisTemplate.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 (压缩列表)😗*当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个)同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用。

  • ​ **skiplist (跳跃表)😗*当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist的读写效率会下降。

1、示例
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd user:1 1 kebe 2 james 3 wade 4 paul
(integer) 4
127.0.0.1:6379> object encoding user:1
"ziplist"
127.0.0.1:6379> zadd user:2 1 kebe 2 james 3 wade 4 paul ...... 130 love
(integer) 130
127.0.0.1:6379> object encoding user:2
"skiplist"

1.6.3 经典场景

​ 有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多个方面的:按照时间、按照播放数量、按照获得的赞数。本节使用赞数这个维度,记录每天用户上传视频的排行榜。

1、添加用户点赞数

​ 例:用户kebe,上传了一个小金人视频,并获得12w个赞,使用有序集合 zadd 和 zincrby 功能:

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd movie kebe 120000
(error) ERR value is not a valid float
127.0.0.1:6379> zadd movie 120000 kebe
(integer) 1
127.0.0.1:6379> zadd movie 100000 james
(integer) 1
127.0.0.1:6379>

​ 如获得一个赞可以使用 zincrby

127.0.0.1:6379> zincrby movie 1 kebe
"120001"
2、取消点赞数
127.0.0.1:6379> zrem movie 1 kebe
(integer) 1
3、获取top10
zrevrangebyscore movie +inf 0 withscores limit 0 10
1) "kebe"
2) "120000"	

1.7 健康管理

1.7.1 单个键管理

1、键重命名 (rename key newKey)
  • 如果newKey 不存在就会直接更新;
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set name kebe
OK
127.0.0.1:6379> rename name nameKebe
OK
127.0.0.1:6379> get nameKebe
"kebe"
127.0.0.1:6379> get name
(nil)
  • 如果newKey 存在那么会将newKey对应的删除掉,再将的 key 替换成 newKey
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set kebe 36
OK
127.0.0.1:6379> set james 38
OK
127.0.0.1:6379> rename james kebe
OK
127.0.0.1:6379> get james
(nil)
127.0.0.1:6379> get kebe
"38"
  • 为了防止被强制执行rename,他还提供了一个命令 renamenx, newKey 不存在才会更新,1-更新成功,0-更新失败
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set kebe 38
OK
127.0.0.1:6379> set james 39
OK
127.0.0.1:6379> renamenx james kebe
(integer) 0
127.0.0.1:6379> renamenx kebe paul
(integer) 1
127.0.0.1:6379> get kebe
(nil)
127.0.0.1:6379> get paul
"38"
127.0.0.1:6379> get james
"39"
2、随机返回一个Key (RandomKey)
127.0.0.1:6379> dbsize
(integer) 2
127.0.0.1:6379> randomkey
"paul"
127.0.0.1:6379> randomkey
"james"
3、键过期
  • expire(设置超时时间)
127.0.0.1:6379> expire paul 500
(integer) 1
  • ttl
    • ≥ 0 ,键剩余的过期时间(ttl:秒 pttl:毫秒)
    • -1 ,键没有设置过期时间
    • -2 ,键不存在
127.0.0.1:6379> ttl paul
(integer) 495
127.0.0.1:6379> ttl james
(integer) -1
127.0.0.1:6379> ttl love
(integer) -2
  • expireat 设置键的秒级过期时间戳 (20210823 21:00)
127.0.0.1:6379> expireat paul 61590542400000
(integer) 1
  • pexpire
127.0.0.1:6379> set kebe 38
OK
127.0.0.1:6379> pexpire kebe 100000
(integer) 1
127.0.0.1:6379> ttl kebe
(integer) 95
  • pexpireat
127.0.0.1:6379> pexpireat kebe 61590542400000
(integer) 1
  • pttl
127.0.0.1:6379> pttl paul
(integer) 61588913832398073
  • persist 清除键的过期时间
127.0.0.1:6379> persist paul
(integer) 1

1.7.2 遍历键

1、全量遍历键 (keys pattern)
    • 代表匹配任意字符
  • [ ]代表匹配部分字符串

  • ?代表匹配一个字符串

127.0.0.1:6379> set kebe 34
OK
127.0.0.1:6379> set love 34
OK
127.0.0.1:6379> dbsize
(integer) 4
127.0.0.1:6379> keys *
1) "paul"
2) "love"
3) "kebe"
4) "james"
2、渐进式遍历(scan cursor [match pattern] [count number]) 推荐使用
  • cursor : 必传 是一个游标,第一次遍历从 0 开始,每次 scan 遍历完都会返回当前游标的值,直到游标值为 0,表示遍历结束
  • match :pattern 可选,它是做一个模式匹配这和keys 的模式匹配很想
  • count : number 可选,它是表明每次要遍历的键个数,默认是 10 ,这个值可以适当增大。
127.0.0.1:6379> scan 0 match "ke*"
1) "0"
2) 1) "kebe"

1.7.3 数据库管理

1、切换数据库 (select num)
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> select 2
OK
127.0.0.1:6379[2]>
2、清除数据库 flushAll/flushdb
  • flushAll 清除所有库 慎用
  • flushdb 清除当前库
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值