Redis中数据类型的使用(hash和list)

news2024/9/30 6:00:49

(一)hash哈希

    我们知道redis中的数据都是以键值对的方式存储的,key全部都是string类型,而value可以是不同的数据结构,其中就包括hash,也就是说,key这一层组织完成后到了value仍然是hash

1.Hash的一些命令

    1)hset

设置hash中指定的字段(filed)和值value

我们首先要确定一个key,然后在这个key的value中,再添加一个hash结构

同时我们可以使用这个命令,同时添加多个key对应的哈希结构value

时间复杂度是O(1)如果插入多组就是O(n)

2)hget

获取hash中指定字段的值

我们需要给定一个key,然后再给定一个key中保存的filed

时间复杂度是O(1),如果我们查询的字段不存在就会返回nil

3)hexists

判断hash中是否有对应的field

返回值如果是1就表示存在,如果是0就表示不存在

时间复杂度也是O(1)

4)  hdel

删除hash中指定的field,我们要注意,del是删除的key,而hdel是删除的field

我们可以通过这个命令,一次性删除多个field

时间复杂度:删除一个元素为O(1),n个元素为O(n)

5)hkeys

获取hash中的所有field

时间复杂度为O(n) ,N为field的个数

6)hvals

获取hash中的所有value

获取hash中的所有值

时间复杂度为O(n),N为field的个数

7)hgetall

获取hash中的field和value

时间复杂度O(n),N为field的个数

8)hmget

   一次获取多个field中的value,我们刚刚的hget一次只能获取一个,而且之前说过,为了保证效率,我们要尽量减少网络的开销,所以我们可以使用hmget来一次获取多个value

   这里其实还有hmset,可以一次性放入多个field和value,但是hset本身支持这个功能,所以这里我们不做说明

时间复杂度O(n),N为field的个数

9)hlen

获取hash中所有field的个数

时间复杂度O(1)

返回值为field的个数

10)hsetnx

在field不存在情况下设置hash中的field和value,如果存在就会失败,与setnx类似

时间复杂度为O(1),0表示失败,1表示成功

11)hincrby

   用来使field对应的value进行+n的操作,我们都知道hash用来存键值对结构,所以当然也可以用来计数

  但是我们使用这个命令时要注意,我们改变的值和增加的值,都需要是整数,不然就会报错

时间复杂度为O(1),返回值为变化后的值

12)hincrbyfloat

就是上一条指令的浮点数版本,用法是一样的,这里不多赘述

命令小结

    我们上述也说了一些,一次查询多条数据的指令,但是我们在使用的时候要注意,我们redis可能做缓存也可能做服务器,所以如果我们查询的数据很多,就会导致阻塞,可能会导致出现服务器一瞬间压力过大引发一系列其他问题,而且我们上述的h系列的命令,必须要保证key对应的value必须是hash类型的

   那如果我们一定要获取到所有的field数据,我们可以使用hscan,这个遍历redis的hash的渐进式遍历的,也就是一次遍历一小部分,分多次遍历所有的field,这样就不会阻塞住redis了

2.hash的内部编码

   hash的内部编码有两种

ziplist(压缩列表):当hash类型的元素个数小于一定值时,redis就会使用ziplist来作为hash的内部实现,使用ziplist可以更加进奏的实现多个元素的连续存储,所以可以很好的节省空间,但是如果我们hash类型元素过多,就会导致读写效率会变得很慢

hashtable(哈希表):当元素个数比较多时,redis就会使用hashtable来作为内部实现,因为我们说元素个数多,就会导致ziplist的读写效率下降,但是hashtable的读写时间复杂度为O(1)

    也就是说,ziplist是用时间换空间,但是hashtable是用空间换时间,而我们之前也说过,空间的话我们现在的硬件还是比较够用的,但是时间还是需要我们尽可能的去节省

3.hash的一些应用场景

1)作为缓存

  我们之前使用的mysql是关系型数据库,用户的属性和信息表现为一个表

  但是我们redis是使用一个个键值对,所以就会通过映射的方式来表示用户的信息,我们可以使用字符串的json格式

但是这样仍然不够直观,我们就可以通过今天的hash类型来存储

缓存方式对比:

   1).如果我们使用原生的string类型

虽然也可以表示用户信息实现也很简单,但是会导致内存的占用量比较大,而且用户信息比较分散,因为每个key都是不同的,不满足高内聚的特点

2).如果我们序列化字符串使用json格式

   优点:针对总是以整体作为操作的信息⽐较合适,编程也简单。同时,如果序列化⽅案选择合适,内存的使⽤效率很⾼

  缺点:我们序列化和反序列化也有一定的开销,如果总操作个别属性就不是很灵活

3).hash类型

优点:简单,灵活,直观,同时可以很方便的存储和获取信息

缺点:在内部涉及到内部编码ziplist和hashtable的转换,可能会对内存造成消耗

(二)list列表

    list就相当于顺序表,支持头插头删,尾插尾删,所以list内部的编码方式并非是一个简单的数据,更像是双端队列

   同时,列表的元素是有序的,这里的有序是指顺序不同会导致结果不同,并不是升序和降序的有序,而且列表中的元素的允许重复的

1.list的一些命令

1)lpush

用来头插到list中(左头右尾),支持同时插入多个元素

时间复杂度O(1),如果插入多个元素就为O(n)n为插入元素的个数

返回值是插入后list的长度

2)lpushx

当key存在时就将元素头插到list中,不存在就直接返回

时间复杂度:只插⼊⼀个元素为O(1),插⼊多个元素为O(N),N为插⼊元素个数.

 返回值:插⼊后list的⻓度。

3)rpush

把一个或多个元素尾插到list中

时间复杂度为O(1),插入N个为O(N)

返回值为list插入后的长度

4)rpushx

当key存在时就把一个或多个元素尾插到list中

时间复杂度:只插⼊⼀个元素为O(1),插⼊多个元素为O(N),N为插⼊元素个数.

返回值:插⼊后list的⻓度

5)lrange

   我们这里的l是代表list并不是left

   获取从start开始到end区间的所有元素,左右都是闭区间,并且因为redis支持负数下标,如果我们要获取到最后一个元素可以使用-1,并且redis下标与数组一样,都是从0开始

同时这里redis有一个很好的点

   我们在c++中,如果下标超出了范围,我们一般会认为这是一个“未定义的行为”可能会导致程序崩溃,也可能会出现不合法或者合法的数据,这就会导致我们不一定会立刻发现问题,但是这种不负责的行为,效率确实是比较高

   在java中,如果我们下标超出范围,会给我们抛出异常,但是因为要给我们多做一步下标合法性的验证,就会导致速度会比较慢,但是我们可以第一时间发现问题

   而redis是尽可能的去获取到给定区间的元素,如果我们给了一个非法区间,比如超出下标,那么redis也会返回可以获取到下标元素的值(拥有鲁棒性,容错能力强)

6)lpop

头删,从list左侧取出元素

时间复杂度:O(1)

 返回值:取出的元素或者nil。

7)rpop

尾删,从list右侧取出元素

时间复杂度:O(1)

 返回值:取出的元素或者nil。

   我们这里要注意,在当前的redis5中并没有count参数,但是redis6.2以后,新增了count参数,描述这一次要删几个元素 

 同时搭配这几个出队入队操作,可以实现,栈,队列,双端队列等数据结构

8)lindex

获取从左数第index位置的元素

时间复杂度:O(N)

 返回值:取出的元素或者nil。

9)linsert

在特定的位置插入元素

   我们发现我们在111签名插入1010,但是有两个111,所以我们会在最前面的一个111前面加

时间复杂度为O(N),返回值为插入后的list长度

10)llen

获取到list的长度

时间复杂度O(1),返回值为list的长度

11)lrem

删除某个值的一些元素

12)ltrim

保留start和stop之间的元素,两边外的元素直接被删除

13)lset

根据下标修改元素

我们如果想在不存在的下标上设置元素会直接返回nil

   如果我们想删除一个指定位置的元素,我们可以通过lset把这个位置的元素设置为一特定的字符,然后通过lrem来进行删除

2.阻塞版本的命令

    blpop和brpop是lpop和rpop的阻塞版本,他们的区别为:

1).如果列表有元素,那么阻塞和非阻塞是一样的,如果没有元素,非阻塞版本会返回nil,阻塞版本会根据阻塞时间,进行阻塞,这是redis可以执行一些别的命令,但是要求执行命令的客户端为阻塞状态。

2).命令中如果设置了多个间,就会从左向右遍历,一旦有一个键对应的列表有元素,就会弹出并且返回

3).如果有多个客户端执行blpop,最先执行命令的客户端会得到弹出的元素

   我们redis中的list就相当于一个阻塞队列,我们之前在多线程上也说到过阻塞队列,但是当时我们需要手动保证线程安全,但是redis的线程安全是通过线程安全的情况,而因为我们redis的空间还是比较大的,一般不考虑队列满的情况

   blpop

lpop的阻塞版本

返回值为列表和取出的元素或者nil

时间复杂度O(1)

 brpop

rpop的阻塞版本

时间复杂度O(1)

返回值为取出的元素或nil

3.lsit的内部编码

1.ziplist(压缩列表)

  我们之前在hash也说过,他的内部编码也是ziplist,ziplist把数据按照更紧凑的压缩形式进行标识,能够很好的节省空间,但是如果数据比较多操作数据的效率就会比较低

2.linkedlist(链表)

   ziplist如果数据多,操作数据的效率会比较低,所以我们可以通过linkedlist来操作数据,虽然这样会使我们占用的空间变大,但是对数据的操作会比较快

  但是这两种方式各有各的好处,有没有一种编码方式可以综合这两种的特点? 

   我们redis在之后使用了quicklist来内部编码list类型,quicklist相当于使list和ziplist的结合,整体还是一个链表,但是链表的每一个节点,是一个ziplist,我们通过链表来保证每一个ziplist都不是很大,这样就可以在节省空间的前提下,尽可能的快速的操作数据

4.使用场景

 消息队列

 我们说list给我们提供了阻塞状态的lpop和rpop,所以我们可以用这个阻塞实现生产者消费者模型,我们生产者客户端用lpush从列表左边插入元素,然后消费者用brpop来阻塞式的去拿队首元素

分频道的消息队列

   redis使用lpush和brpop命令,但是通过不同键模拟不同频道的概念,不同的消费者可以通过brpop不同的键

 作为数组

  我们可以把list作为类似数组的一个结构,来存储多个元素,具体要如何组织数据,需要根据实际业务来确定

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2178856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业级移动门户的多样化选择:为数字化转型赋能

在当今数字化转型的浪潮中,企业级移动门户(Enterprise Mobile Portal)被广泛应用于企业的日常运营中。它们为企业提供了一个集中、统一的移动应用与数据访问平台,帮助提升工作效率、增强实时沟通并改善员工体验。随着企业对灵活性…

Qt --- 系统相关---事件、文件操作、多线程编程、网络编程、多媒体

虽然Qt是跨平台的C开发框架,Qt的很多能力其实是操作系统提供的。只不过Qt封装了系统API。程序是运行在操作系统上的,需要系统给我们提供支撑。 事件、文件操作、多线程编程、网络编程、多媒体(音频、视频)。 一、事件 信号槽&a…

数学期望专题

9.29 - 10.6 更新时间约持续一周 优惠券 Coupons 题目链接:优惠券 Coupons 假设我们某个情况下,我们已经有了 k 种图案,在这个条件下,获得一个新图案需要 天,那我们要求的就是 。由于已经有了 k 种图案&#xff0c…

【热门主题】000002 案例 JavaScript网页设计案例

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…

技术速递|Java on Azure Tooling 8月更新 - Java 体验在 Azure 容器应用程序正式发布

作者:Jialuo Gan 排版:Alan Wang 大家好,欢迎阅读 Java on Azure 开发者工具8月份更新。在本次更新中,我们将介绍在 IntelliJ IDEA 中 Azure Toolkit 对 Azure App Service 提供托管身份支持(Managed Identity&#xf…

AIGC教程:如何用Stable Diffusion+ControlNet做角色设计?

前言 对于生成型AI的画图能力,尤其是AI画美女的能力,相信同行们已经有了充分的了解。然而,对于游戏开发者而言,仅仅是漂亮的二维图片实际上很难直接用于角色设计,因为,除了设计风格之外,角色设…

class 029 重要排序算法的总结

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。 这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐. https://space.bilibili.com/8888480?spm_id_f…

Springboot+PostgreSQL+MybatisPlus存储JSON或List、数组(Array)数据

项目架构 SpringbootPostgreSQLMybatisPlus 从Mongodb转过来的项目,有存储json数据的需求,但是在mybatis-plus上会出点问题 报错: Error updating database. Cause: org.postgresql.util.PSQLException 字段 “” 的类型为 jsonb, 但表达式的…

Junit和枚举ENUM

断言机制,JAVA中的断言机制是一种用于检查程序中某个条件是否为真的机制。它可以在程序运行时检查某个条件是否满足,如果不满足则会抛出AssertionError异常。 在java中,断言机制默认是关闭的。所以会输出u。 断言机制只是为了用来吃调试程序的&#xff0…

【设计模式-中介者模式】

定义 中介者模式(Mediator Pattern)是一种行为设计模式,通过引入一个中介者对象,来降低多个对象之间的直接交互,从而减少它们之间的耦合度。中介者充当不同对象之间的协调者,使得对象之间的通信变得简单且…

fiddler抓包13_响应后断点 - 篡改响应

课程大纲 原理 响应后断点(After Response Breakpoint):Fiddler拦截、篡改服务器返回的响应,再返回给客户端。 应用场景 1.分析服务器响应数据 2.测试前端对特定返回的处理、展示 3.模拟网络中断、不稳定场景 单个断点 VS 全局…

信息安全数学基础(22)素数模的同余式

前言 信息安全数学基础中的素数模的同余式是数论中的一个重要概念,它涉及到了素数、模运算以及同余关系等多个方面。 一、基本概念 素数:素数是指只能被1和它本身整除的大于1的自然数。素数在密码学中有着广泛的应用,如RSA加密算法就依赖于大…

2024年企业博客SEO趋势与策略

随着互联网的快速发展和搜索引擎算法的不断演进,企业博客作为内容营销和SEO(搜索引擎优化)的重要载体,正面临着前所未有的机遇与挑战。进入2024年,企业若想通过博客在激烈的市场竞争中脱颖而出,就必须紧跟S…

verilog实现FIR滤波系数生成(阶数,FIR滤波器类型及窗函数可调)

在以往采用 FPGA 实现的 FIR 滤波功能,滤波器系数是通过 matlab 计算生成,然后作为固定参数导入到 verilog 程序中,这尽管简单,但灵活性不足。在某些需求下(例如捕获任意给定台站信号)需要随时修改滤波器的…

产品管理- 互联网产品(5):运营知识与技能

了解运营 1、运营的基础是产品认清受众,切实解决问题、用户需求 2、运营活动贯穿产品的整个生命周期 3、找准用户,建立MVP 4、明确产品的应用场景。用户在何场景下基于何种需求使用产品?务必短流程 5、AARRR模型 6、运营管理流程类似产品管理…

【CAM350】使用总结 <一>{ 光绘Gerber 对齐 }

〇、废话: 由于allegro和CAM350之间参数设置的问题;导致钻孔层和数据交付生产出现数据问题,或者同一个工程前后迭代,需要找出差别。 一、打开CAM350,打开两份光绘文件 二、增加工艺边后,不是很方便的找出区别&#x…

水波荡漾效果+渲染顺序+简单UI绘制

创建场景及布置 创建新场景Main,在Main场景中创建一个plane物体,命名为WaterWavePla,具体数值及层级面板排布如下: 编写脚本 创建一个文件夹,用于存放脚本,命名Scripts,创建一个子文件夹Effect,存放特效相关脚本,创建…

[Linux]:线程(二)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 与Windows环境不同,我们在linux环境下需要通过指令进行各操作&…

LQR算法核心思想

本章以倒立摆为解决目的 什么是线性二次型控制器(LQR) 开环系统 即状态变量的倒数 系统的状态空间矩阵A * 系统状态变量x A状态矩阵:描述系统本身物理特性的一个矩阵,它是由系统本身的机械结构、物理结构决定的,无法…