【redis】Redis数据类型(二)Hash类型

ops/2024/9/25 23:12:00/

目录

  • Hash类型介绍
    • 特性
    • hash 的内部编码方式/底层结构
      • hashtable
      • ziplist
      • listpack
    • 适用场景
      • 举例
    • 常用命令
      • hset
        • 示例
      • hsetnx
        • 示例:
      • hmset
        • 示例
      • hget
        • 示例
      • hmget
        • 示例
      • hgetall
        • 示例
      • hdel
        • 示例
      • hlen
        • 示例
      • hexists
        • 示例
      • hincrby
        • 示例
      • hincrbyfloat
        • 示例
      • hkeys
        • 示例
      • hvals
        • 示例

Hash类型介绍

Hash 类型是一种键值对集合,这种数据类型适合用于存储对象

特性

  • 键值对集合:Hash 类型可以存储多个键值对,每个键都有一个对应的值。
  • 二进制安全:Hash 类型的键和值都是二进制安全的,这意味着它们可以包含任何数据,包括二进制数据。
  • 大容量:单个 Hash 类型可以存储超过 4 亿个键值对。
  • 高效的查找速度:无论 Hash 中存储了多少数据,查找某个键的速度都非常快。

hash 的内部编码方式/底层结构

Redis 的 Hash 类型会根据实际情况在压缩列表(ziplist)和散列表(hashtable)之间进行切换,这主要取决于两个配置参数:hash-max-ziplist-entries 和 hash-max-ziplist-value。

  • hash-max-ziplist-entries:这个参数用于设置压缩列表可以存储的最大节点数量。如果一个 Hash 类型的元素数量超过这个值,那么就会从压缩列表切换到散列表。默认值为 512;
  • hash-max-ziplist-value:这个参数用于设置压缩列表中每个节点的最大值大小(以字节为单位)。如果一个 Hash 类型的任何元素的大小超过这个值,那么就会从压缩列表切换到散列表。默认值为 64。

hashtable

  • 最基本的哈希表(不是 java 标准库中的 HashTable),redis 内部对哈希表的实现方式和 java 中的哈希表可能不太一样,但是整体思想都是一样的;时间上复杂度O(1),但是空间上会有一定的浪费(hash 是一个数组,数组上有些位置有元素,有些位置没有元素).
  • 当 Hash 类型存储的字段和值的数量较多,或者字段和值的字符串长度较长时,Redis 会选择使用散列表作为底层实现。散列表是一种常见的键值对映射结构,它通过一个散列函数将键映射到一个桶中,然后在桶中进行查找。这种方式的优点是查找和修改数据的性能较高,但是占用的内存也较多。
  • Redis 的散列表(hash table)是一种常见的键值对映射结构,它通过一个散列函数将键映射到一个桶中,然后在桶中进行查找。Redis 的散列表使用链表法解决哈希冲突,即当多个键映射到同一个桶时,将它们存储在同一个链表中

ziplist

压缩列表,当哈希表里的元素比较少的时候,就优化成了 ziplist 了,在Redis7.0之前使用,特点是内存占用教少,能够节省空间,但是读写元素的速度比较慢;

  • 如果 hash 中的元素比较少,使用 ziplist 表示. 元素比较多的时候使用 hashtable 表示.
  • 每个 value 值的长度都比较短的,使用 ziplist 表示. 如果某个 value 长度太长,也会转化成 hashtable.
  • 压缩的本质就是对数据进行重新编码,不同的数据有不同的特点,结合这些特点,重新编码后,就能够缩小体积
  • 例如 abbcccdddd 重新编码就变成了 1a2b3c4d.

listpack

紧凑列表,在Redis7.0版本之后取代了ziplist,同样也是hash到达一定阀值后转换为hashtable。

适用场景

  1. 存储对象:Hash 类型可以存储多个键值对,非常适合用于存储对象。例如,你可以使用 Hash 类型存储用户的信息,如用户名、密码、邮箱等;
  2. 数据分析:你可以使用 Hash 类型存储各种统计数据,例如用户的行为数据,然后进行数据分析;
  3. 社交网络:在社交网络应用中,你可以使用 Hash 类型存储用户的朋友列表、粉丝列表等
  4. 购物车场景的使用。使用用户ID作为key,商品ID作为field,商品数量或规格等信息作为value,便于快速增删改查购物车中的商品项
  5. 缓存配置信息:应用程序的配置信息,如各种设置参数,可以集中存储在Hash中,方便统一管理和实时更新
  6. 权限列表管理: 用Hash存储用户的权限信息,key为用户ID,field表示权限标识符,value为权限状态(如允许/禁止)。
  7. 进度存储:如小说阅读进度、视频播放进度等场景,key可以是用户ID+资源ID组合,field为资源唯一标识,value为对应的进度值。
  8. 关系模型数据建模:当需要在Redis中模拟关系型数据库中的一对多或者多对多关系时,Hash可以作为一个轻量级的解决方案,简化数据结构设计
  9. 计数器集合:当需要统计一组相关联的数据项的不同维度计数时,可以使用Hash存储每个维度的计数值。

举例

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

常用命令

命令描述
hset key field valuefiled的不存在新增并返回1,如果filed已经存在就覆盖更新并返回0
hsetnx key field value如果filed不存在则设置值为字符串value并返回1,否则不做任何操作返回0
hgetall key field获取这个key的所有field-value,返回结果为数组
hdel key field删除field的value,删除成功返回1,删除失败返回0
hdel key删除key的所有field-value,删除成功返回1,删除失败返回0
hmset k1 f1 v1 k2 f2 v2 …批量操作一次性新增或更新多个field
hmget f1 f2 …批量操作一次性获取多个field的value
hexists key field判断field是否存在,存在返回1,否侧返回0
hsetnx key field valuefield不存在则设置值,否则不操作
hvals key获取hash结构的所有值

hset

  • 语法:hset key field value
  • 解释:
    • 将哈希表 key 中的域 field 的值设为 value 。
    • 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
    • 如果域 field 已经存在于哈希表中,旧值将被覆盖
  • 时间复杂度:O(1)
  • 返回值:
    • 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。
    • 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。
示例
127.0.0.1:6379[3]> hset mywebsite csdn "zhoujl.blog.csdn.net"
(integer) 1
127.0.0.1:6379[3]> hset mywebsite csdn "https://zhoujl.blog.csdn.net"
(integer) 0
127.0.0.1:6379[3]>

hsetnx

  • 语法:hsetnx key field value
  • 解释:
    • 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。
    • 若域 field 已经存在,该操作无效。
    • 如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。
  • 时间复杂度:O(1)
  • 返回值:
    • 设置成功,返回 1 。
    • 如果给定域已经存在且没有操作被执行,返回 0 。
示例:
127.0.0.1:6379[3]> hsetnx user username admin
(integer) 1
127.0.0.1:6379[3]> hsetnx user userage 20
(integer) 1
127.0.0.1:6379[3]> hsetnx user username root
(integer) 0
127.0.0.1:6379[3]>

hmset

  • 语法:hmset key field value [field value …]
  • 解释:
    • 同时将多个 field-value (域-值)对设置到哈希表 key 中。
    • 此命令会覆盖哈希表中已存在的域。
    • 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
  • 复杂度:O(N), N 为 field-value 对的数量。
  • 返回值类型:
    • 如果命令执行成功,返回 OK 。
    • 当 key 不是哈希表(hash)类型时,返回一个错误。
示例
127.0.0.1:6379[3]> hmset role roleId 1 roleName admin
OK
127.0.0.1:6379[3]> hget role roleId
"1"
127.0.0.1:6379[3]> hget role roleName
"admin"
127.0.0.1:6379[3]>

hget

  • 语法:hget key field
  • 解释:返回哈希表 key 中给定域 field 的值
  • 时间复杂度:O(1)
  • 返回值:
    • 给定域的值。
    • 当给定域不存在或是给定 key 不存在时,返回 nil 。
示例
127.0.0.1:6379[3]> hset site redis redis.com
(integer) 1
127.0.0.1:6379[3]> hget site redis
"redis.com"
127.0.0.1:6379[3]> hget site mysql
(nil)
127.0.0.1:6379[3]>

hmget

  • 语法:hmget key field [field …]
  • 解释:
    • 返回哈希表 key 中,一个或多个给定域的值。
    • 如果给定的域不存在于哈希表,那么返回一个 nil 值。
    • 因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
  • 时间复杂度:O(N), N 为给定域的数量。
  • 返回值:一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样
示例
127.0.0.1:6379[3]> hmset pet dog anpei cat mimi
OK
127.0.0.1:6379[3]> hmget pet dog cat penguin
1) "anpei"
2) "mimi"
3) (nil)
127.0.0.1:6379[3]>

hgetall

  • 语法:hgetall key
  • 解释
    • 返回哈希表 key 中,所有的域和值。
    • 在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
  • 时间复杂度:O(N), N 为哈希表的大小。
  • 返回值:
    • 以列表形式返回哈希表的域和域的值。
    • 若 key 不存在,返回空列表。
示例
127.0.0.1:6379[3]> hset city zz zhengzhou
(integer) 1
127.0.0.1:6379[3]> hset city hz hangzhou
(integer) 1
127.0.0.1:6379[3]> hgetall city
1) "zz"	# 属性/域
2) "zhengzhou" 	# 值
3) "hz"
4) "hangzhou"
127.0.0.1:6379[3]>

hdel

  • 语法:hdel key field [field …]
  • 解释:
    • 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
    • 注:在 Redis2.4 以下的版本里, HDEL 每次只能删除单个域,如果你需要在一个原子时间内删除多个域,请将命令包含在 MULTI / EXEC 块内。
  • 时间复杂度:O(N), N 为要删除的域的数量。
  • 返回值:被成功移除的域的数量,不包括被忽略的域。
示例
127.0.0.1:6379[3]> hgetall city1) "zz"2) "zhengzhou"3) "hz"4) "hangzhou"5) "kf"6) "kaifeng"7) "ly"8) "luoyang"9) "bj"
10) "beijing"
11) "sh"
12) "shanghai"
127.0.0.1:6379[3]> hdel city sh
(integer) 1
127.0.0.1:6379[3]> hdel city hz bj
(integer) 2
127.0.0.1:6379[3]> hgetall city
1) "zz"
2) "zhengzhou"
3) "kf"
4) "kaifeng"
5) "ly"
6) "luoyang"
127.0.0.1:6379[3]>

hlen

  • 语法:hlen key
  • 解释:返回哈希表 key 中域的数量。
  • 时间复杂度:O(1)
  • 返回值:
    • 哈希表中域的数量。
    • 当 key 不存在时,返回 0 。
示例
127.0.0.1:6379[3]> hgetall city
1) "zz"
2) "zhengzhou"
3) "kf"
4) "kaifeng"
5) "ly"
6) "luoyang"
127.0.0.1:6379[3]> hlen city
(integer) 3
127.0.0.1:6379[3]>

hexists

  • 语法:hexists key field
  • 解释:查看哈希表 key 中,给定域 field 是否存在。
  • 时间复杂度:O(1)
  • 返回值:
    • 如果哈希表含有给定域,返回 1 。
    • 如果哈希表不含有给定域,或 key 不存在,返回 0 。
示例
127.0.0.1:6379[3]> hexists city sh
(integer) 0
127.0.0.1:6379[3]> hexists city zz
(integer) 1
127.0.0.1:6379[3]>

hincrby

  • 语法:hincrby key field increment
  • 解释:
    • 为哈希表 key 中的域 field 的值加上增量 increment 。
    • 增量也可以为负数,相当于对给定域进行减法操作。
    • 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。
    • 如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。
    • 对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。
    • 本操作的值被限制在 64 位(bit)有符号数字表示之内
  • 时间复杂度:O(1)
  • 返回值:执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。
示例
# increment 为正数
127.0.0.1:6379[3]> HEXISTS counter page_view # 对空域进行设置
(integer) 0
127.0.0.1:6379[3]> HINCRBY counter page_view 200
(integer) 200
127.0.0.1:6379[3]> HGET counter page_view
"200"
# increment 为负数
127.0.0.1:6379[3]> HGET counter page_view
"200"
127.0.0.1:6379[3]> HINCRBY counter page_view -50
(integer) 150
127.0.0.1:6379[3]> HGET counter page_view
"150"
# 尝试对字符串值的域执行 HINCRBY 命令
127.0.0.1:6379[3]> HSET myhash string hello,world # 设定一个字符串值
(integer) 1
127.0.0.1:6379[3]> HGET myhash string
"hello,world"
127.0.0.1:6379[3]> HINCRBY myhash string 1 # 命令执行失败,错误。
(error) ERR hash value is not an integer
127.0.0.1:6379[3]> HGET myhash string # 原值不变
"hello,world"

hincrbyfloat

  • 语法:hincrbyfloat key field increment
  • 解释:
    • 为哈希表 key 中的域 field 加上浮点数增量 increment 。
    • 如果哈希表中没有域 field ,那么 HINCRBYFLOAT 会先将域 field 的值设为 0 ,然后再执行加法操作。
    • 如果键 key 不存在,那么 HINCRBYFLOAT 会先创建一个哈希表,再创建域 field ,最后再执行加法操作。
    • 当以下任意一个条件发生时,返回一个错误:
      • 域 field 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
      • 域 field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)
    • HINCRBYFLOAT 命令的详细功能和 INCRBYFLOAT 命令类似,请查看 INCRBYFLOAT 命令获取更多相关信息。
  • 时间复杂度:O(1)
  • 返回值:执行加法操作之后 field 域的值。
示例
# 值和增量都是普通小数
127.0.0.1:6379[3]> HSET mykey field 10.50
(integer) 1
127.0.0.1:6379[3]> HINCRBYFLOAT mykey field 0.1
"10.6"
# 值和增量都是指数符号
127.0.0.1:6379[3]> HSET mykey field 5.0e3
(integer) 0
127.0.0.1:6379[3]> HINCRBYFLOAT mykey field 2.0e2
"5200"
# 对不存在的键执行 HINCRBYFLOAT
127.0.0.1:6379[3]> EXISTS price
(integer) 0
127.0.0.1:6379[3]> HINCRBYFLOAT price milk 3.5
"3.5"
127.0.0.1:6379[3]> HGETALL price
1) "milk"
2) "3.5"
# 对不存在的域进行 HINCRBYFLOAT
127.0.0.1:6379[3]> HGETALL price
1) "milk"
2) "3.5"
127.0.0.1:6379[3]> HINCRBYFLOAT price coffee 4.5 # 新增 coffee 域
"4.5"
127.0.0.1:6379[3]> HGETALL price
1) "milk"
2) "3.5"
3) "coffee"
4) "4.5

hkeys

  • 语法:hkeys key
  • 解释:返回哈希表 key 中的所有域。
  • 时间复杂度:O(N), N 为哈希表的大小。
  • 返回值:
    • 一个包含哈希表中所有域的表。
    • 当 key 不存在时,返回一个空表。
示例
# 哈希表非空
127.0.0.1:6379[3]> HMSET website google www.google.com yahoo www.yahoo.com
OK
127.0.0.1:6379[3]> HKEYS website
1) "google"
2) "yahoo"
# 空哈希表/key 不存在
127.0.0.1:6379[3]> EXISTS fake_key
(integer) 0
127.0.0.1:6379[3]> HKEYS fake_key
(empty list or set)

hvals

  • 语法:hvals key
  • 解释:返回哈希表 key 中所有域的值。
  • 时间复杂度:O(N), N 为哈希表的大小。
  • 返回值:
    • 一个包含哈希表中所有值的表。
    • 当 key 不存在时,返回一个空表。
示例
# 非空哈希表
127.0.0.1:6379[3]> HMSET website google www.google.com yahoo www.yahoo.com
OK
127.0.0.1:6379[3]> HVALS website
1) "www.google.com"
2) "www.yahoo.com"
# 空哈希表/不存在的 key
127.0.0.1:6379[3]> EXISTS not_exists
(integer) 0
127.0.0.1:6379[3]> HVALS not_exists
(empty list or set)

http://www.ppmy.cn/ops/27518.html

相关文章

Java毕业设计 基于SpringBoot vue养老院管理系统 微信小程序

Java毕业设计 基于SpringBoot vue养老院管理系统 微信小程序 SpringBoot 养老院管理系统 功能介绍 小程序 护工登录注册 忘记密码 护工信息维护 首页 图片轮播 床位调动申请 床位展示 床位详情 床位分配 房间展示 公告信息 公告详情 健康信息 请假申请 离职申请 后台管理 登…

虚拟机软件:VMware VirtualBox Hyper-v

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 虚拟机软件是程序员必备的开发…

如何在Spring Boot中配置数据库密码加密

如何在Spring Boot中配置数据库密码加密? alibaba/druid Wiki GitHub 使用ConfigFilter alibaba/druid Wiki GitHub 巧用Druid数据源实现数据库连接密码的加密解密功能 import com.alibaba.druid.filter.config.ConfigTools;public class Testttt {public stat…

《MySQL对库的基本操作》

文章目录 一、查看数据库列表查看数据库中的所有表想知道当前处于哪个数据库里 二、创建一个数据库三、删除一个数据库知道两个集1.字符集2.校验集修改数据库的字符集和编码集 不同的校验码对数据库的影响四、数据库的备份与恢复注意事项:备份数据库中的表 总结 一、…

Rust特征对象

一、特征对象是什么,有什么用,怎么用 1、特征对象是什么 特征对象指向实现了 某种特征的类型的实例,这种映射关系是存储在一张表中,可以在运行时通过特征对象找到具体调用的类型方法 可以通过 & 引用或者 Box 智能指针的方式…

大语言模型的涌现能力

文章目录 涌现能力涌现能力与扩展法则的关系GPT 系列模型的技术演变早期探索规模扩展能力增强性能跃升 涌现能力 大语言模型的涌现能力被非形式化定义为“在小型模型中不存在但在大模型中出现的能力”,具体是指当模型扩展到一定规模时,模型的特定任务性能…

[C++]11版本新特性4:包装器:function、bind

前言 本文将介绍包装器(适配器) 引入 我们之前接触过函数指针、仿函数、lambda 但他们各有优劣,有没有一种方法可以对众多类型进行打包封装,这样就可以提高效率了 那就是function包装器 包装器 function 包装器本质是一个类…

http请求,结合springboot

目录 简单参数&实体参数 get请求 post请求 简单参数&实体参数【总结】 springboot中接受简单参数 RequestParam注解 实体参数接收 数组集合参数 数组接收 集合接收 数组集合参数 【总结】 日期参数请求 JSON参数请求 路径参数请求 所有请求参数类型总…