- 基本的语言都提供了哈希类型,只是叫法不同(哈希,字典,关联数组),哈希类型是指键值本身又是一个键值对。
- 哈希类型中的映射关系叫field-value,value是指field对应的值,不是键对应的值。
一、哈希命令
1.1、设置值:set
1.2、获取值:hget
1.3、删除field :hdel
- 语法:hdel key field[ field … ]
- 说明:可以删除一个或多个field
127.0.0.1:6379> hset user:1 name test-name
(integer) 1
127.0.0.1:6379> hget user:1 name
"test-name"
127.0.0.1:6379> hset user:2 name test-name2
(integer) 1
127.0.0.1:6379> hget user:2 name
"test-name2"
127.0.0.1:6379> hget user2 name1
(nil)
127.0.0.1:6379> hget useer:2 name1
(nil)
127.0.0.1:6379> hdel user: 1 name
(integer) 0
1.4、计算field的个数
127.0.0.1:6379> hset user name test-name
(integer) 1
127.0.0.1:6379> hset user age 12
(integer) 1
127.0.0.1:6379> hset user addrss sz
(integer) 1
127.0.0.1:6379> hlen user
(integer) 3
1.5、批量获取,批量设置
- 语法:hmget key field [ field … ]
- 语法:hmset key field value [ fild value … ]
127.0.0.1:6379> hmset field name test-name age 23 address sz
OK
127.0.0.1:6379> hmget field name age address
1) "test-name"
2) "23"
3) "sz"
127.0.0.1:6379> hlen field
(integer) 3
1.6、判断field是否存在:hexists
- 语法:hexists key field
- 返回值:0表示不存在,1表示存在
127.0.0.1:6379> hexists fild ts
(integer) 0
127.0.0.1:6379> hexists fild name
(integer) 0
127.0.0.1:6379> hexists field name
(integer) 1
127.0.0.1:6379> hexists field ts
(integer) 0
1.7、获取所有field
1.8、获取所有value
1.9、获取所有个field-value
- 语法:hgetall key
- 注意:
- 如果使用hgetall如果元素过多会存在阻塞redis的可能,如果需要的是部分数据可以采用hmget,
- 如果一定需要全部数据可以采用hscan获取,该命令会渐进式遍历哈希类型
127.0.0.1:6379> hkeys field
1) "name"
2) "age"
3) "address"
127.0.0.1:6379> hvals field
1) "test-name"
2) "23"
3) "sz"
127.0.0.1:6379> hgetall field
1) "name"
2) "test-name"
3) "age"
4) "23"
5) "address"
6) "sz"
127.0.0.1:6379>
1.10、hincrby hibcrbyfloat
- 语法:hibcrby key field
- 语法:hincrbyfloat key field
127.0.0.1:6379> hget field age
"46"
127.0.0.1:6379> hincrby field age 11
(integer) 57
127.0.0.1:6379> hget field age
"57"
127.0.0.1:6379> hincrbyfloat field age 2.33
"59.33"
127.0.0.1:6379> hget field age
"59.33"
1.11、计算value的字符串长度(redis3.2以上)
127.0.0.1:6379> hget field name
"test-name"
127.0.0.1:6379>hstrlen field name
(integer) 9
二、 内部编码
- 哈希类型的内部编码有两种:ziplist,hashtable
ziplist(压缩列表):
- 当哈希类型元素小于hash-max-ziplist-entries配置(512)、同时授予值小于hash-max-ziplist-value配置(64字节),redis会使用ziplist作为哈希的内部实现
- ziplist使用更加紧凑的结构实现多个元素的连续存储,在内存节省中比hashtable更加优秀
hashtable(哈希表):
- 当哈希类型无法满足ziplist的条件是,redis会使用hashtable作为哈希的内部实现。
ziplist与hashtable的转换
- 1、当前field个数较少没有打的value时内部编码为ziplist
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding hashkey
"ziplist"
- 2、当value大于64字节内部编码会有ziplist转换成hashtable
127.0.0.1:6379> hset hashkey f3 "one string skjahfd hkjshkd shakfj 长度传递长度 长度skldfj sdf"
(integer) 1
127.0.0.1:6379> OBJECT encoding hashkey
"hashtable"
- 3、当前filed个数超过512个时内部编码也会又ziplist转换成hashtable
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2 f3 v3 f4 v4 f5 v5 ... f513 v513
OK
127.0.0.1:6379> OBJECT encoding hashkey
"hashtable"
三、使用场景
[
{
"id":1,
"name":"test name1",
"address":"sz"
},
{
"id":2,
"name":"test name2",
"address":"sz"
}
]
- 说明:相比使用字符串序列化缓存用户数据哈希类型会更加直观,可以给每个用户的id定义为后缀,多对field-value对应每个用户的属性
public User getUser(Long id){
String key = "user_info:" + id;
String userMap = redis.hgetAll(key);
if(usermMap != null){
}else{
}
}
- 注意:
- 哈希类型是稀疏的,关系型数据库是完全结构化的。
-
- 如:哈希类型每个键可以有不同的field,而关系型数据库一旦添加新的列所有的行都有为其设置值。
- 关系型数据库库做复杂的关系查询。
三种方案实现方法和优缺点分析
1、原生字符串类型:
set user: name test-name
set user: age 12
set user: address sz
- 优点:简单直观,每个属性都支持更新操作
- 缺点:占用过多的键,内存占用量较大,用户信息内聚比较差
2、序列化字符串类型:
set user serialize(user)
- 优点:简化编程,如果合理使用序列化可以提高内存的使用效率
- 缺点:序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据进行反序列化,更新后再序列化到redis中
3、哈希类型:
- 每个用户属性使用一对filed-value,但是只用一个键保存
hmset user name test-name age 12 address sz
- 优点:简单直观,如果使用合理可以减少内存空间的使用
- 缺点:要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会消耗更多内存