几乎所有的编程语言都提供了哈希(hash)类型,它们的叫法可能是哈 希、字典、关联数组。在Redis中,哈希类型是指键值本身又是一个键值对结构,形如value={{field1,value1},...{fieldN,valueN}},Redis键值对和哈希类型二者的关系可以用下图来表示。

常用命令
1.设置值:hset key field value
如果设置成功会返回1,反之会返回0。此外Redis提供了hsetnx命令,它们的关系就像set和setnx命令一样,只不过作用域由键变为field。
2.获取值:hget key field
如果键或field不存在,会返回nil.
3.删除field:hdel key field [field ...]
hdel会删除一个或多个field,返回结果为成功删除field的个数
4.计算field个数:hlen key
**5.批量设置或获取field-value:hmget key field [field ...] hmset key field value [field value ...]
hmset和hmget分别是批量设置和获取field-value,hmset需要的参数是key 和多对field-value,hmget需要的参数是key和多个field
6.判断field是否存在:hexists key field
7.获取所有field:hkeys key
hkeys命令应该叫hfields更为恰当,它返回指定哈希键所有的field
8.获取所有value:hvals key
9.获取所有的field-value:hgetall key
hkeys命令应该叫hfields更为恰当,它返回指定哈希键所有的field
在使用hgetall时,如果哈希元素个数比较多,会存在阻塞Redis的可能。 如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型,hscan后续介绍
10.自增:hincrby hincrbyfloat
hincrby和hincrbyfloat,就像incrby和incrbyfloat命令一样,但是它们的作用域是filed。
11.计算value的字符串长度(需要Redis3.2以上):hstrlen key field
注:
哈希类型中的映射关系叫作field-value,注意这里的value是指field对应的值,不是键对应的值,请注意value在不同上下文的作用
典型使用场景
下图为关系型数据表记录的两条用户信息,用户的属性作为表的列,每条用户信息作为行。

如果将其用哈希类型存储,如图所示。

相比于使用字符串序列化缓存用户信息,哈希类型变得更加直观,并且在更新操作上会更加便捷。可以将每个用户的id定义为键后缀,多对fieldvalue对应每个用户的属性,类似如下伪代码:
UserInfo getUserInfo(long id){
//用户id作为key后缀
userRedisKey = "user:info:" + id;
//使用hgetall获取所有用户信息映射关系
userInfoMap = redis.hgetAll(userRedisKey);
//UserInfo userInfo;
if (userInfoMap != null) {
//将映射关系转换为UserInfo
userInfo = transferMapToUserInfo(userInfoMap);
} else {
//从MySQL中获取用户信息
userInfo = mysql.get(id);
//将userInfo变为映射关系使用hmset保存到Redis中
redis.hmset(userRedisKey, transferUserInfoToMap(userInfo));
//添加过期时间
redis.expire(userRedisKey, 3600);
}
return userInfo;
}
但是需要注意的是哈希类型和关系型数据库有两点不同之处:
- 哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型 每个键可以有不同的field,而关系型数据库一旦添加新的列,所有行都要为其设置值(即使为NULL)。
- 关系型数据库可以做复杂的关系查询,而Redis去模拟关系型复杂查询开发困难,维护成本高。
开发人员需要将两者的特点搞清楚,才能在适合的场景使用适合的技术。到目前为止,我们已经能够用三种方法缓存用户信息,下面给出三种方案的实现方法和优缺点分析。
- 原生字符串类型:每个属性一个键。
set user:1:name tom set user:1:age 23 set user:1:city beijing
优点:简单直观,每个属性都支持更新操作。
缺点:占用过多的键,内存占用量较大,同时用户信息内聚性比较差,所以此种方案一般不会在生产环境使用。 - 序列化字符串类型:将用户信息序列化后用一个键保存。
set user:1 serialize(userInfo)
优点:简化编程,如果合理的使用序列化可以提高内存的使用效率。
缺点:序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据取出进行反序列化,更新后再序列化到Redis中。 - 哈希类型:每个用户属性使用一对field-value,但是只用一个键保存。
hmset user:1 name tomage 23 city beijing
优点:简单直观,如果使用合理可以减少内存空间的使用。
缺点:要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会消耗更多内存。
















