Redis哈希类型详解:从基础命令到实际应用

devtools/2024/9/29 21:55:12/

引言

前边介绍了 Redis 中字符串类型,现在接上篇文章继续学习 Redis 哈希类型的命令和实际应用

哈希(Hash)类型是一种非常实用的数据结构,以字段-值对的形式存储多个键值对。这里将详细介绍 Redis 哈希类型的使用方法、内部编码以及在实际开发中的应用场景


1. 什么是哈希类型?

哈希类型在 Redis 中是一种特殊的键值对结构,它的值本身又是一个键值对集合。你可以把它想象成一个小型的数据库表,其中每个键代表一条记录,而每条记录包含多个 field 和对应的 value。

例如:

  • user:1 可以作为一个键,表示用户ID为1的信息。
  • 在这个键下,可以有多个字段如 nameagecity 等,每个字段都有对应的值。

2. 基本命令详解

1. 设置和获取字段
  • HSET - 设置或更新哈希表中指定字段的值。

    HSET user:1 name "James" age 28 city "Beijing"

    如果字段已经存在,HSET 会更新其值;如果字段不存在,则创建新的字段并设置值。

  • HGET - 获取哈希表中指定字段的值。

    HGET user:1 name

    返回指定字段的值,如果字段不存在则返回 nil

2. 检查字段是否存在
  • HEXISTS - 检查给定字段是否存在于哈希表中。
    HEXISTS user:1 gender
    返回 1 表示字段存在,0 表示字段不存在。
3. 删除字段
  • HDEL - 从哈希表中删除一个或多个字段。
    HDEL user:1 city
    返回成功删除的字段数量。
4. 查看所有字段和值
  • HKEYS - 获取哈希表中的所有字段名。

    HKEYS user:1

    返回所有字段名的列表。

  • HVALS - 获取哈希表中的所有字段值。

    HVALS user:1

    返回所有字段值的列表。

  • HGETALL - 获取哈希表中所有的字段及其对应的值。

    HGETALL user:1

    返回所有字段和对应值的列表,格式为 [field1, value1, field2, value2, ...]

5. 批量操作
  • HMGET - 获取哈希表中多个字段的值。

    HMGET user:1 name age

    返回指定字段的值列表,不存在的字段返回 nil

  • HMSET - 设置哈希表中多个字段的值。(注意:从 Redis 4.0 开始,推荐使用 HSET 代替 HMSET

    HMSET user:1 name "John" age 29
6. 字段计数
  • HLEN - 获取哈希表中字段的数量。
    HLEN user:1
    返回哈希表中字段的总数。
7. 自增操作
  • HINCRBY - 将哈希表中字段的整数值增加指定数量。

    HINCRBY user:1 score 10

    返回增加后的值。

  • HINCRBYFLOAT - 将哈希表中字段的浮点数值增加指定数量。

    HINCRBYFLOAT user:1 score 10.5

    返回增加后的值。


3. 内部编码

Redis 会根据哈希表中元素的数量和大小自动选择最合适的内部编码来优化内存使用和性能:

  • ziplist(压缩列表) - 当哈希表中的元素较少且每个值都不大时,Redis 会选择 ziplist 作为内部编码。这种方式占用更少的内存,并且对于小数据集具有较高的性能。

    • 默认配置:hash-max-ziplist-entries = 512 和 hash-max-ziplist-value = 64 字节。
  • hashtable(哈希表) - 当哈希表中的元素较多或者某个值较大时,Redis 会切换到 hashtable,以保证高效的读写操作。

    • 这种方式在处理大数据集时更加高效,时间复杂度为 O(1)。

可以通过 OBJECT ENCODING 命令查看特定键的内部编码方式:

OBJECT ENCODING user:1ziplisthashtable

4. 使用场景

哈希类型非常适合用来缓存用户信息等实体对象。相比于直接使用字符串序列化整个对象,哈希类型提供了更细粒度的操作能力,比如单独更新用户的某一个属性而不必重新序列化整个对象。

示例代码

以下是一个使用 Java 伪代码示例,展示如何利用哈希类型来实现用户信息的缓存

public class UserService {private final Jedis jedis; // 假设使用 Jedis 客户端public UserService(Jedis jedis) {this.jedis = jedis;}public UserInfo getUserInfo(long uid) {// 构建 Redis 键String key = "user:" + uid;// 从 Redis 中尝试获取用户信息Map<String, String> userInfoMap = jedis.hgetAll(key);// 如果缓存命中if (userInfoMap != null && !userInfoMap.isEmpty()) {// 构建并返回用户信息对象return new UserInfo(userInfoMap.get("name"),Integer.parseInt(userInfoMap.get("age")),userInfoMap.get("city"));}// 缓存未命中,从数据库中获取UserInfo userInfo = database.getUserById(uid);// 如果数据库中没有该用户if (userInfo == null) {// 返回 404 错误throw new NotFoundException("User not found");}// 将用户信息保存到 Redis,并设置过期时间Map<String, String> fields = new HashMap<>();fields.put("name", userInfo.getName());fields.put("age", String.valueOf(userInfo.getAge()));fields.put("city", userInfo.getCity());jedis.hmset(key, fields);jedis.expire(key, 3600); // 设置过期时间为 1 小时// 返回用户信息return userInfo;}
}

5. 缓存方式对比

  1. 原生字符串类型 - 每个属性一个独立的键。简单但可能导致大量键不好管理,而且内存占用较高。

    SET user:1:name "James"
    SET user:1:age 23
    SET user:1:city "Beijing"

    优点:实现简单,针对个别属性变更也很灵活。

    缺点:占用了过多的键,内存占用量较大,同时用户信息在 Redis 中比较分散,低内聚。

  2. 序列化字符串类型 - 如 JSON 格式,适合整体操作,但在处理局部更新时效率较低。

    SET user:1 "{\"name\":\"James\",\"age\":23,\"city\":\"Beijing\"}"

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

    缺点:本身序列化和反序列需要一定开销,同时如果总是操作个别属性则非常不灵活。

  3. 哈希类型 - 结合了前两者的优点,既灵活又高效,特别适用于需要频繁更新单个属性的场景。

    HMSET user:1 name "James" age 23 city "Beijing"

    优点:简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。

    缺点:需要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,可能会造成内存的较大消耗。


结论

以上就是 Redis 中哈希类型相关的知识,后续会继续更新,感谢阅览!!


http://www.ppmy.cn/devtools/118908.html

相关文章

dlinject分析,一种不使用ptrace的linux代码注入

原理是通过直接操作Linux进程的内存&#xff0c;将一个动态链接库&#xff08;.so 文件&#xff09;注入到正在运行的进程中。这种注入过程通常涉及高级的系统编程技巧&#xff0c;涉及到操作系统的低层机制。以下是对该脚本的详细分析&#xff1a; 1. ELF文件解析 ELF&#…

解决 Pandas 中的 XLRDError:处理 “Excel xlsx file; not supported” 错误

解决 Pandas 中的 XLRDError&#xff1a;处理 “Excel xlsx file; not supported” 错误 在处理数据分析任务时&#xff0c;使用 Python 的 Pandas 库来读取 Excel 文件是一种常见的做法。然而&#xff0c;从 Pandas 1.2.0 版本开始&#xff0c;默认使用的 xlrd 库不再支持 .x…

平安养老险肇庆中心支公司开展“2024年金融教育宣传月”活动

为加强消费者金融教育宣传&#xff0c;切实提升社会公众金融素养&#xff0c;有效防范化解金融风险&#xff0c;营造和谐健康金融环境&#xff0c;在肇庆金融监管分局指导下&#xff0c;平安养老险肇庆中心支公司开展金融教育宣传月暨反洗钱宣传月系列活动。 9月11日&#xff…

架构师论文备考-论软件系统架构评估

题目&#xff1a;论软件系统架构评估 对于软件系统&#xff0c;尤其是大规模的复杂软件系统来说&#xff0c;软件的系统架构对于确保最终系统的质量具有十分重要的意义&#xff0c;不恰当的系统架构将给项目开发带来高昂的代价和难以避免的灾难。对一个系统架构进行评估&#x…

RK3588主板PCB设计学习(四)

DDR4相比于DDR3升级的地方在于控制线增加了几条&#xff0c;数据线数量没有变。并且功耗更低&#xff0c;电压更低&#xff0c;读写速度更快&#xff1a; 看左边&#xff0c;一把数据线分组&#xff1a; 11根走线是1组&#xff1a; 这里很经典&#xff0c;认真复习&#xff1a;…

计算机网络(第二章 物理层)

文章目录 1.物理层的基本概念2.数据通信的基础知识2.1数据通信系统模型2.2有关信道的基本概念2.3信道极限容量 3.物理层3.2引导性传输媒体3.3非引导性传输媒体 4.信道复用技术4.1频分复用、时分复用和统计时分复用4.2波分复用 5.宽带接入技术 本文首先讨论物理层的基本概念。然…

R包:ggspatial空间画图

ggplot2语法的空间图形画图 Spatial data plus the power of the ggplot2 framework means easier mapping. 加载R包 # install.packages("ggspatial")library(ggplot2) library(ggspatial) load_longlake_data()Using layer_spatial() and annotation_spatial() g…

C语言 | Leetcode C语言题解之第437题路径总和III

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ //递归遍历树节点&#xff0c;判断是否为有效路径 int dfs(struct TreeNode * root, int ta…