0.前言
- 在Redis中,哈希范例是指值本⾝是⼀个键值对布局,形如key="key",value={{field1, value1}, ..., {fieldN, valueN}}
- 字符串和哈希范例对比:存储一个uid为1的用户对象,姓名James,年龄28
- 留意:哈希范例中的映射关系通常称为field-value,⽤于区分Redis整体的键值对(key-value), 留意这⾥的value是指field对应的值,不是键(key)对应的值
1.常见下令
1.HSET
- 功能:设置hash中指定的字段(field)的值(value)
- 语法:`HSET key field value [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 [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 [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.利用场景
- 关系型数据表记录的两条用户信息
- 映射关系表⽰⽤⼾信息:可以将每个⽤⼾的id定义为键后缀,多对field-value对应⽤⼾的各个属性
- 优势:相⽐于使⽤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
- 关系数据库可以做复杂的关系查询,⽽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两种内部编码的转换,大概会造成内存的较⼤斲丧
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |