Redis数据类型——string(应用篇)

174 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情


哈喽,大家好,我是一条。

Redis 作为一种非关系型数据库,以 key , value 的形式存储数据。这使它的查询复杂度为 O(1) 。

其中 key 永远是 string 类型,我们所说的 Redis 数据类型 其实是指 value 类型。

Redis 共有 5 大基本数据类型:string(字符串)、hash(哈希)、list(列表)、set(集合)及 zset (有序集合)。

随着版本更新,又增加了 Geo 、hyperloglog 、bitmap。

本文主要介绍 string 的一些命令和应用,下一篇会解读 string 类型的源码。

命令

推荐一个网站,可作为 Redis 命令速查手册:rediesfans

string 类型用 Java 语言来说就是 Map<String,String>,是使用最为广泛的类型。

前面在安装时为大家演示过set k1 abc,这其实就是添加了一个 string 类型的键值对。get k1就是查询,类似 Java 中的 set、get 方法。

那么如何修改呢?只需要重新赋值即可。

> set k1 abcd
OK
> get k1
abcd

思考🤔一个问题:

如果我此时 set k2 abcd,类比 Java 的 String 类型,会不会在内存再存储一份 abcd

下一节分析源码时会讲到。

言归正传,如果我想拼接连个字符串怎么办?append帮我们实现。如果 key 不存在,会报错。

> append k1 ef
6
> get k1
abcdef
> append k3
ERR wrong number of arguments for 'append' command

再思考🤔一个问题:

append k1 ef后返回一个6,猜测应该是字符串的长度,那是怎么计算的呢,每次都 for 循环吗?

同样分析了源码就恍然大悟了。

计算长度:strlen

> STRLEN k1
6

自增自减,即Java中的i++,i--,如果是非数字的字符串会报错。

> set k3 12
OK
> INCR k3
13
> decr k3
12
> incr k1
ERR value is not an integer or out of range

再再思考🤔一个问题:

同样是 string 类型, Redis 是怎么知道是不是数字的?

同样分析了源码就恍然大悟了。

过期时间:即到时间自动删除。ttl查看剩余时间, -2 代表已过期,-1 代表永不过期。

> setex k4 20 v4
OK
> ttl k4
16
> ttl k4
12
> get k4
null
> ttl k4
-2
> ttl k1
-1
​

还剩直接删除了,del搞定

> del k1
1
> get k1
null

关于string 的命令其实还有,可以到我推荐的网站详细阅读,下面我们聊聊 string 的应用。

应用

1.简单的作为缓存

不需要高并发,也不需要大数据,就是平平无奇的一个缓存,也可能带来大的提升。

思考这样一个场景:

对接过飞书开发的同学都知道,调用大部分飞书接口之前都要先获取 token 这必然会降低我们自己接口的响应速度。

我们都知道 token 是有过期时间的,这正对应 Redis 的 setex ,所以解决方案如下:

  • 将 token 获取之后存入 Redis ,并设置过期时间。
  • 获取 token 之前先去 Redis 查一下,查到就不再调飞书接口。

伪代码如下:

    public String getToken() {
        // 先从redis取
        Object redisToken = redisService.getCacheObject(TOKEN_KEY);
        if (ObjectUtil.isNotEmpty(redisToken)) {
            return redisToken.toString();
        }
      
        // 调用飞书,省略部分代码
        String response = HttpRequest.post(appConfig.getTokenUrl())
                .header(headers)
                .body(param.toJSONString())
                .execute()
                .body();
        JSONObject data = JSONObject.parseObject(response);
        String token = data.getString("tenant_access_token");
        
        // 存入redis,防止二次获取,提高响应时间。
        redisService.setCacheObject("message-set-token", token, data.getLong("expire"), TimeUnit.SECONDS);
        return token;
    }

同样的,用户登录的 token 也可以如此处理,不过要搭建高可用的 Redis 集群,防止服务不可用导致全部用户登录失效。

2.统计阅读量

前面提到过自增操作,这用来统计阅读量再合适不过,广义来说就是作为计数器。

伪代码如下:

public void likeArticle(String articleId) {
        Long increment = redisTemplate.opsForValue().increment(CACHE_ARTICLE + articleId,1);
        log.info("----------increment:{}",increment);
    }

点击一次加一,同时返回当前阅读量。

3.分布式锁

大名鼎鼎的分布式锁其实就是利用setnx+过期时间实现,这部分会在后面详细讲解。

总结

学完本章,希望大家马上就在开发中用上 Redis ,已经用的思考一下在高并发下会不会有问题。

精雕细刻出佳品,千修百改出华章。好的架构不是设计出来,而是演变出来的。

下一篇聊聊 string 的源码实现——简单动态字符串。

记得点赞关注!