最新:Redis持久化——AOF日志redis
Redis对象——哈希(Hash)cookie
哈希在不少编程语言中都有着很普遍的应用,而在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里面的元素 |
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
不少电商网站都会使用 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
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官方文档》
关注下方公众号,回复“Redis”,可得Redis相关学习资料