[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]