前言

Redis 是目前互联网后端的热门中间件之一,在许多方面都有深度的应用,作为后端开发熟练掌握该技术是十分有必要的。

Redis 的五种数据类型是:1、String(字符串);2、Hash(哈希);3、List(列表);4、Set(集合);5、Sort Set (有序集合)。其余的用的比较少,本文暂不涉及。

其中,String(字符串)是 Redis 中最基本的数据类型,一个 Key 对应一个 Value。其它的几个常用结构如下简图所示:

图1

关于 Redis 的安装搭建和在 Linux 中的原生命令操作,可以见我的另一篇文章:https://www.cnblogs.com/Apluemxa/p/16465276.html

注:以下内容都是基于 RedisTemplate 在项目中的实际使用进行说明。

  1. 引入 pom 依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  2. 新建序列化配置类

    @Configuration
    public class RedisTemplateConfiguration {
    //需要单独声明该 Bean 的 name,否则使用 JDK 自带的序列化配置会导致显示乱码
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String , Object> template = new RedisTemplate<>();
    RedisSerializer<String> redisSerializer = new StringRedisSerializer();
    template.setConnectionFactory(redisConnectionFactory);
    //key 序列化
    template.setKeySerializer(redisSerializer);
    //value 序列化
    template.setValueSerializer(redisSerializer);
    //value 的 hash 序列化
    template.setHashValueSerializer(redisSerializer);
    //key 的 hash 序列化
    template.setHashKeySerializer(redisSerializer);
    return template;
    }
    }
  3. 新建 RedisTemplate 工具类

    作用是封装一些常用的方法(只给两个简单的方法示例,直接注入 RedisTemplate 效果也一样),同时在方法里进行一些判空、异常捕获、输出日志等操作。

    @Slf4j
    @Component
    public class RedisTemplateUtils { @Resource
    private RedisTemplate<String, Object> redisTemplate; /**
    * 放入普通缓存,并设置过期时间
    * @param key 键
    * @param value 值
    * @param expireTime 过期时间(秒) ,time 要大于0,如果小于等于0,将设置无限期
    * @return true 成功,false 失败
    */
    public Boolean set(String key, Object value, long expireTime) {
    try {
    if (expireTime > 0) {
    redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
    } else {
    set(key, value);
    }
    return Boolean.TRUE;
    } catch (Exception e) {
    log.error("exception when set Redis key {}. ", key, e);
    return Boolean.FALSE;
    }
    } /**
    * 获取普通缓存
    * @param key 键
    * @return Object 类型的值
    */
    public Object get(String key) {
    return Optional.ofNullable(redisTemplate.opsForValue().get(key)).orElse(null);
    }
    }

一、String 类型

字符串类型是 Redis 中最基本的数据存储类型,它是一个由字节组成的序列,在 Rediss 中是二进制安全的。这意味着该类型可以接受任何格式数据,如 JPEG 图像链接数据和 Json 对象格式的信息等等。

它是标准的 key-value,通常用于存储字符串、整数和浮点。其中单个 value 内可容纳最高达512MB的数据。

‎由于所有数据都在单个对象中,Redis 中的字符串操作速度非常快。‎‎基本的‎‎ Redis 命令(如 ‎‎SET‎‎、‎‎GET‎‎ 和 ‎‎DEL‎‎)允许对字符串值执行一些基本操作:

  • ‎SET 键值‎‎ ‎‎– 设置指定键的值。‎
  • ‎GET 键‎‎ ‎‎– 检索指定键的值。‎
  • ‎DEL 键‎‎ ‎‎– 删除给定键的值。‎
    @Resource
private RedisTemplateUtils redisTemplateUtils;
/**
* String 类型的存/取
* @return
*/
@Override
public String testStringType() {
String redisStr = "";
//设置键、值以及过期时间30分钟
if (redisTemplateUtils.set(SysConstant.TEST_REDIS_KEY, UUIDUtils.generateUUID(), 1800)){
//由于获得的值是 Object 类型的,所以需要强转成 String 类型
redisStr = (String) redisTemplateUtils.get(SysConstant.TEST_REDIS_KEY);
System.out.println(redisStr);
}
return redisStr;
}

注:其中需要先注入 RedisTemplateUtils 来保证引入 RedisTemplate。

Redis 的可视化客户端(我用的是Another Redis Desktop Manager,开源免费)中的数据可以看到已经写入了,如下图1-1所示:

图1-1

常见的应用场景:存储用户 token 信息、缓存热点关键数据、统计站点访问量、计算当前在线人数等。


二、List 类型

Redis 列表是简单的字符串列表,按照插入顺序排序。我们可以添加一个元素到列表的头部(左边)或者尾部(右边)。

Redis 的列表允许用户从列表的两端推入或者弹出元素,列表由多个字符串值组成的有序可重复的序列,是一个链表的结构,所以向列表两端添加元素的时间复杂度为O(1),获取越接近两端的元素速度就越快。

这意味着,即使有数以千万计的元素列表,也可以极快地速度获得10条在头部或者尾部的记录。

该种类型的‎‎字符串链表‎‎可以执行一些常见的基本操作,例如:‎

  • ‎leftPushAll‎ – 将值从左边推送到列表(倒序)。‎
  • ‎rightPushAll‎ – 将值从右边推送到列表(顺序)。‎
  • ‎RANGE‎‎ – 根据 key 获取 value。‎
  • ‎LPOP/RPOP‎‎ ‎‎– 用于显示和删除列表两端的值。‎
  • ‎LINDEX‎‎ ‎‎– 获取列表中指定位置(下标)的值。
    @Resource
private StudyMapper studyMapper; //为了方便举例,这里直接用 RedisTemplate 实现,就不用自己封装的工具类了,效果是一样的
@Resource
private RedisTemplate<String, String> redisTemplate; /**
* 测试 List 类型
* @return
*/
@Override
public List<String> testListType() {
LambdaQueryWrapper<Study> wrapper = new LambdaQueryWrapper<>();
//先将数据库的实体类型列表转换为 String 类型
List<String> stringList = studyMapper.selectList(wrapper).stream()
.map(val -> val.convertExt(String.class))
.collect(Collectors.toList());
//数据先存后取
if (redisTemplate.opsForList().leftPushAll(SysConstant.TEST_REDIS_LIST_KEY, stringList) > NumberUtils.LONG_ZERO){
//参数为0和-1,代表取出所有值
List<String> list = redisTemplate.opsForList().range(SysConstant.TEST_REDIS_LIST_KEY,0,-1);
return list;
}
return null;
}

在 Redis 可视化客户端的数据如下图2-1所示:

图2-1

常见的应用场景:xx最新排行榜前十;消息队列(订阅/发布模式)等。


三、Hash 类型

Redis hash 是一个键值对(其中 key 数大于等于 value 数)的集合。Redis hash 是一个 field 和 value 都为 String 类型的映射表,hash 特别适合用于存储集合对象。

Redis的Hash结构可以使你像在数据库中 update 一个属性那样,只修改某一项属性值。和 String 有点像,但 value 中存放的是一张表,一般用于多个个体的详细事项排列,String 也可以做到,但要比 hash 麻烦许多。

以下是该结构相关的一些方法,允许更改单个或多个字段:

  • ‎HSET‎‎ – 根据键向哈希表放入数据。‎
  • ‎HGET‎‎ –根据 key 获取各个值。‎
  • ‎HGETALL‎‎ ‎‎– 获取整个哈希表的内容。‎
  • ‎HDEL‎‎ – 从哈希中删除现有的键值对。‎
    @Resource
private ShoppingCarMapper shoppingCarMapper; /**
* 测试 Hash 类型
* @return
*/
@Override
public Map<Object, Object> testHashType() {
LambdaQueryWrapper<ShoppingCar> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ShoppingCar::getUserId,"1656698374114156635");
//组装一个 key 为 商品Id、value 为该用户购物车信息 list 的 Map 对象
Map<String, String> hashMap = new HashMap<>();
shoppingCarMapper.selectList(wrapper).forEach(val -> hashMap.put(val.getGoodId(), val.convertExt(String.class)));
//redis 的 key 为用户 userId
if(redisTemplateUtils.hset("1656698374114156635",hashMap,1800)){
return redisTemplateUtils.hget("1656698374114156635");
}
return null;
}

在 Redis 可视化客户端的数据如下图3-1所示:

图3-1

常见的应用场景:频繁更改的数据,如用户的购物车、用户会话信息等;适合使用 Hash 结构存储的数据:如城市与所处经纬度、城市与所处的学校等。


四、Set 结构

Redis 的 Set 是 String 类型的无序不重复集合。Set的底层是借助哈希表来实现的,所以添加、删除、查找的复杂度都是 O(1)。

所谓 Set 集合就是一堆不重复值的组合,并且这些值的摆放是没有顺序的。

如:在微博应用中,可以将某个用户所有的关注人存入一个集合中,将其所有的粉丝存入另一个集合。

Redis还提供了诸如collection、union和differences等操作,使得实现诸如commandism、poperhike、secondfriends这样的功能变得很容易,或者可以选择将结果返回,还是将它们保存到新的集合中。

可以使用‎‎以下命令‎‎添加、删除、检索和检查等,对集合中的内容进行操作:‎

  • ‎SADD‎‎ – 向集合中添加一个或多个元素。‎
  • SISMEMBER‎ – 判断set集合中是否包含指定值。‎
  • ‎SMEMBERS‎‎ – 根据 key 获取集合中所有元素。‎
  • ‎SREM‎‎ – 从集合中删除现有元素。
    @Resource
private UserMapper userMapper; /**
* 测试 Set 类型
* @return
*/
@Override
public Set<Object> testSetType() {
//这里从数据库中构建出一个 String[]
String[] strs = userMapper.selectList(new LambdaQueryWrapper<User>()
.select(User::getUnionId)).stream()
.map(val -> val.convertExt(String.class)).toArray(String[]::new);
//可以放单个的 String 字符串,也可以一次性放一个 String[]
if (redisTemplateUtils.sSet(SysConstant.TEST_REDIS_SET_KEY, strs) > NumberUtils.LONG_ZERO){
Set<Object> result = redisTemplateUtils.sGet(SysConstant.TEST_REDIS_SET_KEY);
return result;
}
return null;
}

在 Redis 可视化客户端的数据如下图4-1所示:

图4-1

常见的应用场景:判断用户是否在线(结合过期时间)、记录文章或者商品的标签(结合去重)、交集/并集寻找共同好友等。


五、Sort Set (Zset)结构

Sorted Set 也叫 Zset ,和 Set 一样也是 String 类型元素的集合,且不允许重复的成员。不同的是每个元素都会携带一个 Double 类型的双精度浮点数。

Zset 正是通过上述的分数来为集合中的成员进行从小到大的排序。Zset的 value 是唯一的,但分数(权重)却可以重复。

以下的一些基本命令可以根据 value 或分数大小进行获取、添加、删除、检索等的操作:‎

  • ‎ZADD‎‎ ‎‎– 将具有分数的元素添加到集合。‎
  • ‎ZRANGE‎‎ ‎‎– 获取经过的排序的集合。‎‎withscores‎‎ ‎‎选项生成实际分数值(从小到大排列)。‎
  • ‎ZRANGEBYSCORE ‎‎– 按照定义的分数范围从集合中获取元素。‎‎withscores‎‎ ‎‎选项生成实际分数值。‎
  • ‎ZREM‎‎ –‎‎从已排序的集中删除元素。
    @Resource
private ShoppingCarMapper shoppingCarMapper;
/**
* 测试 ZSet 类型
* @return
*/
@Override
public Set<String> testZSetType() {
//这里先初始化一个 Redis 中对 ZSet 专门设置的类型对象,其中一个元素是 value,另一个是 Double 类型的 Score 分数
Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
shoppingCarMapper.selectList(new LambdaQueryWrapper<ShoppingCar>()
.eq(ShoppingCar::getUserId, "1656698374114156635"))
.forEach(val -> typedTupleSet.add(new DefaultTypedTuple<>(val.convertExt(String.class), val.getPrice())));
if (redisTemplate.opsForZSet().add("1656698374114156635", typedTupleSet) > NumberUtils.LONG_ZERO){
//这里是按照分数从小到大的顺序获取集合,reverseRange() 则顺序相反
Set<String> result = redisTemplate.opsForZSet().range("1656698374114156635", 0, -1);
return result;
}
return null;
}

在 Redis 可视化客户端的数据如下图5-1所示:

图5-1

常见的应用场景:根据游戏段位(作为Score)生成排行榜、按照发布时间范围(作为Score)来展示文章、按照商品价格(作为Score)去排序等。


六、文章小结

本文介绍了关于 Redis 的几个基本数据结构,以及在 Spring 项目中 RedisTemplate 的一些简单使用。

如有错误,还望指正,同时也欢迎大家在评论区说出自己的想法。

最后,我有计划写一篇关于上述几种数据结构在真实场景中具体应用文章,尝试着给出一些解决方案,还请期待。

参考文档:

【主流技术】聊一聊 Redis 的基本结构和简单应用(一)的更多相关文章

  1. 【主流技术】Redis 在 Spring 框架中的实践

    前言 在Java Spring 项目中,数据与远程数据库的频繁交互对服务器的内存消耗比较大,而 Redis 的特性可以有效解决这样的问题. Redis 的几个特性: Redis 以内存作为数据存储介质 ...

  2. 【收藏用】--切勿转载Java处理XML的三种主流技术及介绍

    原帖地址 : http://www.ibm.com/developerworks/cn/xml/dm-1208gub/ XML (eXtensible Markup Language) 意为可扩展标记 ...

  3. Java 处理 XML 的三种主流技术及介绍

    Java 处理 XML 的三种主流技术及介绍 原文地址:https://www.ibm.com/developerworks/cn/xml/dm-1208gub/ XML (eXtensible Ma ...

  4. GIAC 技术大会 Redis 演讲文字稿

    附录:https://mp.weixin.qq.com/s/mvAkPXBayAzT_RWFdsOt5A 观众朋友们,我是来自掌阅的工程师钱文品,今天我带来的是分享主题是:Redis 在海量数据和高并 ...

  5. python操作三大主流数据库(12)python操作redis的api框架redis-py简单使用

    python操作三大主流数据库(12)python操作redis的api框架redis-py简单使用 redispy安装安装及简单使用:https://github.com/andymccurdy/r ...

  6. 【Redis源代码剖析】 - Redis内置数据结构之压缩字典zipmap

    原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/51111230 今天为大家带来Redis中zipmap数据结构的分析,该结构定义在 ...

  7. NB-IoT将成为未来5G物联网主流技术

    日前,我国完成了IMT-2020(5G)候选技术方案的完整提交.据悉,在提交的方案中,NB-IoT技术被正式纳入5G候选技术集合,预计2020年6月ITU将正式宣布5G技术方案的诞生.而NB-IoT也 ...

  8. 在线直播: .NET与物联网主流技术探秘 初识IoT!

    DNT精英论坛暨.NET北京俱乐部是由资深.NET专家和社区活跃分子发起的技术论坛,以“分享.成长.合作.共赢”为原则,致力于打造一个领先的技术分享平台和成长交流生态.本次活动由aelf赞助支持,刘洪 ...

  9. 消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ&Redis的重点介绍与简单应用 消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下 ...

  10. 进击的Python【第十一章】:消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下消息队列的基本思路. 还记得原来写过Queue的文章,不管是线程queu ...

随机推荐

  1. 24. 从零用Rust编写正反向代理,细说HTTP行为中的几种定时器

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现 ...

  2. Educational Codeforces Round 127 (Rated for Div. 2) E. Preorder

    设\(f[v]\)是以结点\(v\)为根的方案数,设左子树的根为\(x\),右子树的根为\(y\),那么如果左右子树完全相同,那么我们交换左右子树对方案没有任何影响,都是: \[f[v] = f[x] ...

  3. Android反编译之修改应用包名

    前言 近期看B站数码区这条视频 [大米]破处理器,它能行吗?K50电竞版评测_哔哩哔哩_bilibili 时,发现了UP主的一个比较骚的操作: 嗯?apk文件可以直接拿来使用修改包名的?作为 Andr ...

  4. 聊聊分布式 SQL 数据库Doris(四)

    FE层的架构都能在网上找到说明. 但BE层的架构模式.一致性保障.与FE层之间的请求逻辑,数据传输逻辑等,我个人暂时没有找到相应的博客说明这些的.当然这些是我个人在学习与使用Doris过程中,对内部交 ...

  5. java笔记——面向对象

    1.概述:面向对象是基于面向过程的编程思想 举例:把大象装进冰箱 2.开发:不断的创建对象,使用对象,指挥对象做事情 3.面向对象特征:封装 , 继承 , 多态 4.类和对象的关系: 类是一组相关的属 ...

  6. weblogic端口号和内存怎么修改?

    在WebLogic中修改端口号和内存分配是一项重要的任务,它涉及到服务器性能和应用程序的可靠性.下面我将详细介绍如何修改WebLogic的端口号和内存设置. 修改端口号 WebLogic使用多个端口来 ...

  7. MDI窗体,打开子窗口的时候关闭其他子窗口及去除MainMenuStrip上自动产生的图标

    去除MDI子窗体最大化后在MainMenuStrip上自动产生的图标和最大化.最小化以及关闭按钮在MainMenuStrip的ItemAdded事件中添加代码如下: 1 private void me ...

  8. 聊聊GLM基座模型的理论知识

    概述 大模型有两个流程:预训练和推理. 预训练是在某种神经网络模型架构上,导入大规模语料数据,通过一系列的神经网络隐藏层的矩阵计算.微分计算等,输出权重,学习率,模型参数等超参数信息. 推理是在预训练 ...

  9. bash shell笔记整理——cat命令

    cat命令的作用 简单来说cat命令用于查看文件内容,但是真正来说cat将给定的文件或者标准输入输出到标准输出中. 这个命令时会经常使用到的,不管是在shell脚本的编写还是linux运维测试中,ca ...

  10. Math数学工具类、向上取整,向下取整,四舍五入,最大值

    package com.guoba.math; public class MathTest { /* Math数学工具类,包含以下方法: .ceil() 向上取整 .floor() 向下取整 .rou ...