前言

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. linux 使用crontab 创建定时任务

    转载请注明出处: 在服务器中需要创建一个定时任务,每天执行去清理很早之前备份的文件,所以想到在linux上创建一个shell脚本,通过linux的 crontab 命令定时去执行该shell脚本,从而 ...

  2. 题解 CF637B

    题目大意: 维护个栈,去重保留最上层 题目分析: 啥也不是,数组模拟 \(\text{stack} + \text{unordered\_map}\) 直接秒掉. 复杂度 \(O(n)\) 代码实现: ...

  3. null 不好,我真的推荐你使用 Optional

    "Null 很糟糕." - Doug Lea. Doug Lea 是一位美国的计算机科学家,他是 Java 平台的并发和集合框架的主要设计者之一.他在 2014 年的一篇文章中说过 ...

  4. Tech Lead 要学会戴着镣铐跳舞

    这不是一篇讨喜的文章,至少不会是你常常看到的例如<成为优秀 Tech Lead 的六个建议>令人欢欣鼓舞的那一类.今天我们聊聊 Tech Lead 所面临的不那么轻松的现实问题 程序员一定 ...

  5. 4. Shell 循环语句

    重点: 条件测试. read. Shell 环境配置. case. for. find. xargs. gzip,bzip2,xz. tar. sed. 1)循环 1.1)循环执行介绍 将某代码段重复 ...

  6. Opencv学习笔记(2)

    图像处理是图像识别过程中重要一环,一张图像可能包括海量的不明确的信息,图像处理的目的是消除图像中无关的信息,恢复有用的真实信息,增强有效信息的可检测性,最大限度地简化数据. 参考知乎文章链接:http ...

  7. Excel表格数据可视化的六大常见方式,看看你都会吗?

    当涉及到Excel表格数据的可视化,有许多不同的方式可以展示和呈现数据.以下是六种常见的Excel表格数据可视化方式的详细介绍. 1. 条形图(Bar Chart) 条形图是一种常见的数据可视化图表类 ...

  8. 神经网络入门篇:详解参数VS超参数(Parameters vs Hyperparameters)

    参数 VS 超参数 什么是超参数? 比如算法中的learning rate \(a\)(学习率).iterations(梯度下降法循环的数量).\(L\)(隐藏层数目).\({{n}^{[l]}}\) ...

  9. MySQL查询语句执行顺序

    注意:理论上select后面的字段别名是不可以在where group by having 等后面使用的,但是MySQL5.7做了相应的优化,group by having 后面可以使用

  10. 【Python微信机器人】第六篇:优化使用方式,可pip安装

    优化内容 这篇不聊技术点,说一下优化后的Python机器人代码怎么使用,优化内容如下: 将hook库独立成一个库,发布到pypi,可使用pip安装 将微信相关的代码发布成另一个库,也可以pip安装 g ...