莫张周刘王 发表于 2024-9-30 06:13:16

[Redis][Hash]详细讲解

0.前言



[*] 在Redis中,哈希范例是指值本⾝是⼀个键值对布局,形如key="key",value={{field1, value1}, ..., {fieldN, valueN}}
[*] 字符串和哈希范例对比:存储一个uid为1的用户对象,姓名James,年龄28
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvZmM3ZWViOWJiOGY1NGRjZjg3NDZhZWQ2M2EzMzk3ZDEucG5n
[*] 留意:哈希范例中的映射关系通常称为field-value,⽤于区分Redis整体的键值对(key-value), 留意这⾥的value是指field对应的值,不是键(key)对应的值
1.常见下令

1.HSET



[*]功能:设置hash中指定的字段(field)的值(value)
[*]语法:`HSET key 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
[*]返回值:本次操作删除的字段个数
[*]时间复杂度:删除一个元素为                                        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
[*]返回值:字段对应的值大概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.利用场景



[*] 关系型数据表记录的两条用户信息
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvYjExMzAzZjQwMGZlNDJlMmE4M2M0YzJlYzBlODMyNDQucG5n
[*] 映射关系表⽰⽤⼾信息:可以将每个⽤⼾的id定义为键后缀,多对field-value对应⽤⼾的各个属性
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvNDE1MGU1OWYxZDUzNGRjMmFkMjRjMjgyMjNkYjNkNGIucG5n
[*] 优势:相⽐于使⽤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
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvYzQ0OWUwNjUxYTc5NGFmYWE0NGRmYTAxNzllMGMzNzUucG5n

[*] 关系数据库可以做复杂的关系查询,⽽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.哈希范例



[*]优点:简单、直观、灵活,尤其是针对信息的局部变更大概获取操作
[*]缺点:需要控制哈希在ziplist和hashtable两种内部编码的转换,大概会造成内存的较⼤斲丧
页: [1]
查看完整版本: [Redis][Hash]详细讲解