Redis对象——哈希(Hash)
哈希在很多编程语言中都有着很广泛的应用,而在Redis中也是如此,在redis中,哈希类型是指Redis键值对中的值本身又是一个键值对结构,形如value=[{field1,value1},...{fieldN,valueN}],其与Redis字符串对象的区别如下图所示:

一、内部编码
哈希类型的内部编码有两种:ziplist(压缩列表),hashtable(哈希表)。只有当存储的数据量比较小的情况下,Redis 才使用压缩列表来实现字典类型。具体需要满足两个条件:
当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)
所有值都小于hash-max-ziplist-value配置(默认64字节)
ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。
有关ziplist和hashtable这两种redis底层数据结构的具体实现可以参考我的另外两篇文章。
二、常用命令
Redis哈希对象常用命令如下表(点击命令可查看命令详细说明)。
| 命令 | 说明 | 时间复杂度 |
|---|---|---|
| HDEL key field [field ...] | 删除一个或多个Hash的field | O(N) N是被删除的字段数量。 |
| HEXISTS key field | 判断field是否存在于hash中 | O(1) |
| HGET key field | 获取hash中field的值 | O(1) |
| HGETALL key | 从hash中读取全部的域和值 | O(N) N是Hash的长度 |
| HINCRBY key field increment | 将hash中指定域的值增加给定的数字 | O(1) |
| HINCRBYFLOAT key field increment | 将hash中指定域的值增加给定的浮点数 | O(1) |
| HKEYS key | 获取hash的所有字段 | O(N) N是Hash的长度 |
| HLEN key | 获取hash里所有字段的数量 | O(1) |
| HMGET key field [field ...] | 获取hash里面指定字段的值 | O(N) N是请求的字段数 |
| HMSET key field value [field value ...] | 设置hash字段值 | O(N) N是设置的字段数 |
| HSET key field value | 设置hash里面一个字段的值 | O(1) |
| HSETNX key field value | 设置hash的一个字段,只有当这个字段不存在时有效 | O(1) |
| HSTRLEN key field | 获取hash里面指定field的长度 | O(1) |
| HVALS key | 获得hash的所有值 | O(N) N是Hash的长度 |
| HSCAN key cursor [MATCH pattern] [COUNT count] | 迭代hash里面的元素 |
三、适用场景
3.1 存储对象
Redis哈希对象常常用来缓存一些对象信息,如用户信息、商品信息、配置信息等。
我们以用户信息为例,它在关系型数据库中的结构是这样的
| uid | name | age |
|---|---|---|
| 1 | Tom | 15 |
| 2 | Jerry | 13 |
而使用Redis Hash存储其结构如下图:

相比较于使用Redis字符串存储,其有以下几个优缺点:
原生字符串每个属性一个键。
set user:1:name Tom
set user:1:age 15
优点:简单直观,每个属性都支持更新操作。
缺点:占用过多的键,内存占用量较大,同时用户信息内聚性比较差,所以此种方案一般不会在生产环境使用。序列化字符串后,将用户信息序列化后用一个键保存
set user:1 serialize(userInfo)
优点:简化编程,如果合理的使用序列化可以提高内存的使用效率。
缺点:序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据取出进行反序列化,更新后再序列化到Redis中。序列化字符串后,将用户信息序列化后用一个键保存
hmset user:1 name Tom age 15
优点:简单直观,如果使用合理可以减少内存空间的使用。
缺点:要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会消耗更多内存。
此外,我们曾经在做配置中心系统的时候,使用Hash来缓存每个应用的配置信息,其在数据库中的数据结构大致如下表
| AppId | SettingKey | SettingValue |
|---|---|---|
| 10001 | AppName | myblog |
| 10001 | Version | 1.0 |
| 10002 | AppName | admin site |
在使用Redis Hash进行存储的时候
新增或更新一个配置项
127.0.0.1:6379> HSET 10001 AppName myblog
(integer) 1
获取一个配置项
127.0.0.1:6379> HGET 10001 AppName
"myblog"
删除一个配置项
127.0.0.1:6379> HDEL 10001 AppName
(integer) 1
3.2 购物车
很多电商网站都会使用 cookie实现购物车,也就是将整个购物车都存储到 cookie里面。这种做法的一大优点:无须对数据库进行写入就可以实现购物车功能,这种方式大大提高了购物车的性能,而缺点则是程序需要重新解析和验证( validate) cookie,确保cookie的格式正确,并且包含的商品都是真正可购买的商品。cookie购物车还有一个缺点:因为浏览器每次发送请求都会连 cookie一起发送,所以如果购物车cookie的体积比较大,那么请求发送和处理的速度可能会有所降低。
购物车的定义非常简单:我们以每个用户的用户ID(或者CookieId)作为Redis的Key,每个用户的购物车都是一个哈希表,这个哈希表存储了商品ID与商品订购数量之间的映射。在商品的订购数量出现变化时,我们操作Redis哈希对购物车进行更新:
如果用户订购某件商品的数量大于0,那么程序会将这件商品的ID以及用户订购该商品的数量添加到散列里面。
//用户1 商品1 数量1
127.0.0.1:6379> HSET uid:1 pid:1 1
(integer) 1 //返回值0代表改field在哈希表中不存在,为新增的field
如果用户购买的商品已经存在于散列里面,那么新的订购数量会覆盖已有的订购数量;
//用户1 商品1 数量5
127.0.0.1:6379> HSET uid:1 pid:1 5
(integer) 0 //返回值0代表改field在哈希表中已经存在
相反地,如果用户订购某件商品的数量不大于0,那么程序将从散列里面移除该条目。
//用户1 商品1
127.0.0.1:6379> HDEL uid:1 pid:2
(integer) 1
3.3 计数器
Redis 哈希表作为计数器的使用也非常广泛。它常常被用在记录网站每一天、一月、一年的访问数量。每一次访问,我们在对应的field上自增1
//记录我的
127.0.0.1:6379> HINCRBY MyBlog 202001 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog 202001 1
(integer) 2
127.0.0.1:6379> HINCRBY MyBlog 202002 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog 202002 1
(integer) 2
也经常被用在记录商品的好评数量,差评数量上
127.0.0.1:6379> HINCRBY pid:1 Good 1
(integer) 1
127.0.0.1:6379> HINCRBY pid:1 Good 1
(integer) 2
127.0.0.1:6379> HINCRBY pid:1 bad 1
(integer) 1
也可以实时记录当天的在线的人数。
//有人登陆
127.0.0.1:6379> HINCRBY MySite 20200310 1
(integer) 1
//有人登陆
127.0.0.1:6379> HINCRBY MySite 20200310 1
(integer) 2
//有人登出
127.0.0.1:6379> HINCRBY MySite 20200310 -1
(integer) 1
小结
本篇文章我们总结了Redis 哈希对象的内部实现、常用命令以及常用的一些场景,那么大家在项目中对Redis哈希对象的使用都有哪些场景呢,欢迎在评论区给我留言和分享,我会第一时间反馈!我们共同学习与进步!
参考
《Redis设计与实现》
《Redis开发与运维》
《Redis官方文档》
-----END-----
Redis对象——哈希(Hash)的更多相关文章
- Redis中的哈希(Hash)
Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 键值 ...
- Redis 命令,键(key),字符串(String),哈希(Hash),列表(List),集合(Set)(二)
Redis 命令 Redis 命令用于在 redis 服务上执行操作. 要在 redis 服务上执行命令需要一个 redis 客户端.Redis 客户端在我们之前下载的的 redis 的安装包中. ...
- redis(八):Redis 哈希(Hash)
Redis 哈希(Hash) Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象. Redis 中每个 hash 可以存储 232 ...
- Python操作redis系列以 哈希(Hash)命令详解(四)
# -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...
- redis 哈希(hash)函数
哈希(hash)函数 hSet 命令/方法/函数 Adds a value to the hash stored at key. If this value is already in the has ...
- 【redis源码阅读】redis对象
结构定义 在redis中,对象的数据结构定义如下: typedef struct redisObject { unsigned type:4; unsgined encoding:4; uns ...
- redist命令操作(二)--哈希Hash,列表List
1.Redis 哈希(Hash) 参考菜鸟教程:http://www.runoob.com/redis/redis-hashes.html Redis hash 是一个string类型的field和v ...
- 一致性哈希(hash)算法
一.算法背景 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正 ...
- Redis对象类型
Redis对象类型 Redis基于基础的数据结构创建的对象: 字符串对象. 列表对象. 哈希对象. 集合对象 有序集合对象. 对象回收:Redis对象系统实现了基于引用计数技术的内存回收机制,当程序不 ...
随机推荐
- VUE四 axios详解
axios的中文文档写的已经很详细 https://www.kancloud.cn/yunye/axios/234845
- VUE三 vue-router(路由)详解
前端路由 根据不同的 url 地址展示不同的内容或页面,无需依赖服务器根据不同URL进行页面展示操作 优点 用户体验好,不需要每次都从服务器全部获取,快速展现给用户 缺点 使用浏览器的前进,后退键的时 ...
- React的路由react-router
意思是:当你写一个web应用时候,应噶install的是react-router-dom,同样的,当你想写一个Native应用时候,需要install的是react-router-native,这两个 ...
- 测试 - 某网站ACCESS数据库注入漏洞
元宵节 团团圆圆总少不了一篇文 测试是否有注入 测试数据库类型 后面不用注释猜到可能是access 验证一下 这里说一下MySQL和ACCESS以及MSSQL的判断语句 MySQL:and len ...
- 使用synchronized修饰静态方法和非静态方法有什么区别
前言 最近被问到了这个问题,第一次回答的也是很不好,在此参考网上答案进行整理记录.供大家学习参考. Synchronized修饰非静态方法 Synchronized修饰非静态方法,实际上是对调用该方法 ...
- RStudio终端操作
转于:https://support.rstudio.com/hc/en-us/articles/115010737148-Using-the-RStudio-Terminal#send 原文是英文版 ...
- Google Flutter Clock 大赛优秀项目推荐
Flutter 在 Google 加持下,如今可以作为跨平台首选了.早在 Flutter 刚刚出现强势苗头,我作为第一批体验了一把,<Flutter 初尝:从 Java 无缝过渡>,不过也 ...
- kafka集群搭建及结合springboot使用
1.场景描述 因kafka以前用的不多,只往topic中写入和读取过数据,这次刚好又要用到,记录下kafka集群搭建及结合springboot使用. 2. 解决方案 2.1 简单介绍 (一)关于kaf ...
- this.current = params.page || 1 (前提是params对象一定要存在)
this.current = params.page || 1 (前提是params对象一定要存在)
- Maven+JSP+Servlet+JDBC+Mysql实现的dbExper宾馆管理系统
本文存在视频版本,请知悉 项目简介 项目来源于:https://github.com/mafulong/databaseExper-hotelMaster 这次分享的也是毕设或课程设计选择一样很多的宾 ...