当前位置: 首页 > article >正文

[Redis][Hash]详细讲解

目录

  • 0.前言
  • 1.常见命令
    • 1.HSET
    • 2.HGET
    • 3.HEXISTS
    • 4.HDEL
    • 5.HKEYS
    • 6.HVALS
    • 7.HGETALL
    • 8.HMGET
    • 9.HLEN
    • 10.HSETNX
    • 11.HINCRBY
    • 12.HINCRBYFLOAT
  • 2.内部编码
    • 1.ziplist(压缩链表)
    • 2.hashtable(哈希表)
  • 3.使用场景
  • 4.缓存方式对比
    • 1.原⽣字符串类型
    • 2.序列化字符串类型
    • 3.哈希类型


0.前言

  • 在Redis中,哈希类型是指值本⾝是⼀个键值对结构,形如key="key",value={{field1, value1}, ..., {fieldN, valueN}}

  • 字符串和哈希类型对比:存储一个uid为1的用户对象,姓名James,年龄28
    请添加图片描述

  • 注意:哈希类型中的映射关系通常称为field-value,⽤于区分Redis整体的键值对(key-value), 注意这⾥的value是指field对应的值,不是键(key)对应的值


1.常见命令

1.HSET

  • 功能:设置hash中指定的字段(field)的值(value)
  • 语法:`HSET key field value [field value]
  • 返回值:添加字段的个数
  • 时间复杂度:插入一组field O ( 1 ) O(1) O(1),插入N组field O ( N ) O(N) O(N)

2.HGET

  • 功能:获取hash中指定字段的值
  • 语法HGET key field
  • 返回值:字段对应的值或者nil
  • 时间复杂度 O ( 1 ) O(1) O(1)

3.HEXISTS

  • 功能:判断hash中是否有指定的字段
  • 语法HEXISTS key field
  • 返回值:1表示存在,0表示不存在

4.HDEL

  • 功能:删除hash中指定的字段
  • 语法HDEL key field [field ...]
  • 返回值:本次操作删除的字段个数
  • 时间复杂度:删除一个元素为 O ( 1 ) O(1) O(1),删除N个元素为 O ( N ) O(N) O(N)

5.HKEYS

  • 功能:获取hash中的所有字段
    • 先根据key找到对应的hash -> O ( 1 ) O(1) O(1)
    • 然后再遍历hash -> O ( N ) O(N) O(N)
  • 语法HKEYS key
  • 返回值:字段列表
  • 时间复杂度 O ( N ) O(N) O(N),N为field的个数
  • 注意:该操作也是存在一定风险的,类似于之前介绍的KEYS

6.HVALS

  • 功能:获取hash中所有的值
  • 语法HVALS key
  • 返回值:所有的值
  • 时间复杂度 O ( N ) O(N) O(N),N为field的个数

7.HGETALL

  • 功能:获取hash中的所有字段以及对应的值
  • 语法HGETALL key
  • 返回值:字段和对应的值
  • 时间复杂度 O ( N ) O(N) O(N),N为field的个数
  • 注意:在使⽤HGETALL时,如果哈希元素个数⽐较多,会存在阻塞Redis的可能
    • 如果只需要获取部分field,可以使⽤HMGET
    • 如果⼀定要获取全部field,可以尝试使⽤HSCAN命令,该命令采⽤渐进式遍历哈希类型

8.HMGET

  • 功能:一次获取hash中多个字段的值
  • 语法HMGET key field [field ...]
  • 返回值:字段对应的值或者nil
  • 时间复杂度:只查询⼀个元素为 O ( 1 ) O(1) O(1),查询多个元素为 O ( N ) O(N) O(N),N为查询元素个数

9.HLEN

  • 功能:获取hash中的所有字段的个数
  • 语法HLEN key
  • 返回值:字段个数
  • 时间复杂度 O ( 1 ) O(1) O(1)

10.HSETNX

  • 功能:在字段不存在的情况下,设置hash中的字段和值
  • 语法HSETNX key field value
  • 返回值:1表示设置成功,0表示失败
  • 时间复杂度 O ( 1 ) O(1) O(1)

11.HINCRBY

  • 功能:将hash中字段对应的数值添加指定的值
  • 语法HINCRBY key field increment
  • 返回值:该字段变化之后的值
  • 时间复杂度 O ( 1 ) O(1) O(1)

12.HINCRBYFLOAT

  • 功能HINCRBY的浮点数版本
  • 语法HINCRBYFLOAT key field increment
  • 返回值:该字段变化之后的值
  • 时间复杂度 O ( 1 ) O(1) O(1)

2.内部编码

1.ziplist(压缩链表)

  • 当哈希类型元素个数⼩于hash-max-ziplist-entries配置(默认512个)、 同时所有值都⼩于hash-max-ziplist-value配置(默认64字节)时,Redis会使⽤ziplist作为哈希的内部实现
  • ziplist使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐hashtable更加优秀

2.hashtable(哈希表)

  • 当哈希类型⽆法满⾜ziplist的条件时,Redis会使⽤hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,⽽hashtable的读写时间复杂度为O(1)
  • 哈希类型的内部编码,以及响应的变化
    • field个数⽐较少且没有⼤的value时,内部编码为ziplist
    • 当有value⼤于64字节时,内部编码会转换为hashtable
    • field个数超过512时,内部编码也会转换为hashtable

3.使用场景

  • 关系型数据表记录的两条用户信息
    请添加图片描述

  • 映射关系表⽰⽤⼾信息:可以将每个⽤⼾的id定义为键后缀,多对field-value对应⽤⼾的各个属性
    请添加图片描述

  • 优势:相⽐于使⽤JSON格式的字符串缓存⽤⼾信息,哈希类型变得更加直观,并且在更新操作上变得更灵活

    UserInfo GetUserInfo(long uid)
    {
    	// 根据 uid 得到 Redis 的键
    	String key = “user:" + uid;
    
    	// 尝试从 Redis 中获取对应的值
    	userInfoMap = Redis 执⾏命令: hgetall key;
    
    	// 如果缓存命中(hit)
    	if (value != null)
    	{
    		// 将映射关系还原为对象形式
    		UserInfo userInfo = 利⽤映射关系构建对象 (userInfoMap);
    		return userInfo;
    	}
    
    	// 如果缓存未命中(miss),从数据库中,根据 uid 获取⽤⼾信息
    	UserInfo userInfo = MySQL 执⾏ SQL : 
    						select * from user_info where uid = <uid>
    
    	// 如果表中没有 uid 对应的用户信息
    	if (userInfo == null)
    	{
    		响应404
    		return null;
    	}
    
    	// 将缓存以哈希类型保存
    	Redis 执⾏命令: 
    		hmset key name userInfo.name age userInfo.age city userInfo.city
    
    	// 写⼊缓存,为了防⽌数据腐烂(rot),设置过期时间为 1 ⼩时
    	Redis 执⾏命令: expire key 3600
    
    	// 返回用户信息
    	return userInfo;
    }
    
  • 需要注意的是哈希类型和关系型数据库有两点不同之处

    • 哈希类型是稀疏的,⽽关系型数据库是完全结构化的

      • 例如:哈希类型每个键可以有不同的field,⽽关系型数据库⼀旦添加新的列,所有⾏都要为其设置值,即使为null
        请添加图片描述
    • 关系数据库可以做复杂的关系查询,⽽Redis去模拟关系型复杂查询

      • 例如:联表查询、聚合查询等基本不可能,维护成本⾼

4.缓存方式对比

  • 目前学习了三种方法缓存用户信息,以下给出三种方案的实现方法和优缺点分析

1.原⽣字符串类型

  • 说明:使⽤字符串类型,每个属性⼀个键
  • 优点:实现简单,针对个别属性变更也很灵活
  • 缺点:占⽤过多的键,内存占⽤量较⼤,同时⽤⼾信息在Redis中⽐较分散,缺少内聚性,所以这种⽅案基本没有实⽤性
  • 示例
    set user:1:name James
    set user:1:age 23
    set user:1:city Beijing
    

2.序列化字符串类型

  • 说明:例如JSON格式
  • 优点:针对总是以整体作为操作的信息⽐较合适,编程也简单。同时,如果序列化⽅案选择合适,内存的使⽤效率很⾼
  • 缺点:本⾝序列化和反序列需要⼀定开销,同时如果总是操作个别属性则⾮常不灵活
  • 示例set user:1 经过序列化后的⽤⼾对象字符串

3.哈希类型

  • 优点:简单、直观、灵活,尤其是针对信息的局部变更或者获取操作
  • 缺点:需要控制哈希在ziplisthashtable两种内部编码的转换,可能会造成内存的较⼤消耗

http://www.kler.cn/a/321166.html

相关文章:

  • 二分搜索的三种方法
  • [Admin] Dashboard Filter for Mix Report Types
  • C++的一些模版
  • 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
  • 【Java基础知识系列】之Java类的初始化顺序
  • ‘视’不可挡:OAK相机助力无人机智控飞行!
  • 828华为云征文 | 在华为云X实例上部署微服务架构的文物大数据管理平台的实践
  • linux命令:显示已安装在linux内核的模块的详细信息的工具modinfo详解
  • 物理学基础精解【7】
  • Docker 容器技术:颠覆传统,重塑软件世界的新势力
  • 【RAG研究1】导言-我打算如何对RAG进行全面且深入的研究
  • 【后端开发】JavaEE初阶——计算机是如何工作的???
  • 职业技能大赛-单元测试笔记(assertThat)分享
  • [SDX35]SDX35如何查看GPIO的Base值
  • 力扣随机一题——所有元音按顺序排序的最长字符串
  • Linux嵌入式驱动开发指南(速记版)---Linux基础篇
  • 【计算机组成原理】实验一:运算器输入锁存器数据写实验
  • Windows系统IP地址设置
  • 小白业主选瓷砖不知道质量好坏怎么办?三种方法交给你
  • 【PyTorch】张量操作与线性回归
  • 【学习笔记】网络设备(华为交换机)基础知识7——查看硬件信息 ① display device 命令详解
  • 【Redis入门到精通七】详解Redis持久化机制(AOF,RDB)
  • UBUNTU20.04安装CH384串口卡驱动
  • 【ARM】SOC的多核启动流程详解
  • 关于在vue2中给el-input等输入框的placeholder加样式
  • 【2024】前端学习笔记9-内部样式表-外部导入样式表-类选择器