域名备案完成了怎么建设网站,制作论坛做网站,楼盘查询,网站副标题【Redis_Day6】Hash类型 Hash类型操作hash的命令hset#xff1a;设置hash中指定的字段#xff08;field#xff09;的值#xff08;value#xff09;hsetnx#xff1a;想hash中添加字段并设置值hget#xff1a;获取hash中指定字段的值hexists#xff1a;判断hash中是否… 【Redis_Day6】Hash类型 Hash类型操作hash的命令hset设置hash中指定的字段field的值valuehsetnx想hash中添加字段并设置值hget获取hash中指定字段的值hexists判断hash中是否有指定的字段hdel删除hash中指定的字段hkeys获取hash中所有的字段hvals获取hash中所有的值hgetall获取hash中所有字段和其对应的值hmget一次获取hash中多个字段的值hlen获取hash中所有字段的个数hincrby给hash中指定字段对应的值 加n(n是整数)hincrbyfloat给hash中指定字段对应的值 加n(n是浮点数)hash相关命令小结 hash内部编码hash的应用作为缓存三种缓存方式对比 高内聚低耦合 Hash类型
⼏乎所有的主流编程语⾔都提供了哈希hash类型它们的叫法可能是哈希、字典、关联数组、映射。
在Redis中哈希类型是指值本⾝⼜是⼀个键值对结构形如keykeyvalue{{field1,value1},…,{fieldN,valueN}}。field不能重复。 哈希类型中的映射关系通常称为field-value⽤于区分Redis整体的键值对key-value使用过程中要注意value在不同上下⽂的作⽤。
如下是字符串和哈希类型的对比 redis自身就是键值对结构。 redis自身的键值对就是通过hash的方式来组织的。 针对一个键值对来说其中的value同样可以是键值对该键值对的类型是hash。
操作hash的命令
使用下列h系列命令的前提key对应的value必须是hash类型。
hset设置hash中指定的字段field的值value
总结hset的用法 hset key field value [field value ...]设置key的值值的类型是hash。对一个key可以一次给它设置多个field-value。返回值是添加的字段field的个数。如果key不存在先创建key。 field-value中的value要求是字符串类型。 在hset命令中设置字段field1的值时如果field1存在那么本次设置的value会覆盖field1原来的值。
hsetnx想hash中添加字段并设置值
hsetnx命令也是给字段设置值但是要求字段不存在才能设置成功也就是在hash中新建字段field1并给它设置值。
总结hsetnx的用法 hsetnx key field1 valuekey中不存在field1添加field1并设置它的值为value并返回1。如果field已存在则操作无效返回0。 命令成功前提是key存在且key中不存在field1。 hget获取hash中指定字段的值
总结hget的用法 hget key1 field1获取key1中field1对应的value。返回值是fileld1对应的值或nil。
hexists判断hash中是否有指定的字段
总结hexists的用法 exists key field去key对应的hash类型的value中找有没有字段field。找到了返回1没找到返回0。
hdel删除hash中指定的字段
总结hdel的用法 hdel key field [field ...]删除key中指定的field可以一次性删除多个。返回值是本次操作成功删除的字段个数。
hdel命令是删除key中指定的字段通用命令del是删除key。
hkeys获取hash中所有的字段
总结hkeys的用法 hkeys key根据key找到对应的hash然后遍历该hash获取hash中的所有字段返回值是字段列表。
hvals获取hash中所有的值
总结hvals的用法 hvals key根据key找到对应的hash然后遍历hash获取hash中所有的值。返回值是值列表。 hkeys和hvals命令操作起来都是存在一定风险的。这两个命令的时间复杂度都是O(N)N是哈希的元素个数如果哈希非常大执行这两个命令的时间会很长会导致redis服务器堵塞无法给其他客户端提供服务。
hgetall获取hash中所有字段和其对应的值
总结hgetall的用法 hgetall key遍历key对应的value中所有的field-value并输出。 hgetall命令也是危险的操作。 在使⽤hgetall时如果哈希元素个数⽐较多会存在阻塞Redis的可能。如果开发⼈员只需要获取部分field可以使⽤hmget如果⼀定要获取全部field可以尝试使⽤hscan命令。 hscan是渐进式遍历即hscan命令遍历hash的时候每次只遍历hash中的一部分连续执行多次hscan命令才能完整整个遍历。hkeyshvalshgetall三个命令遍历hash的时候都是一次性遍历完全部hash。
hmget一次获取hash中多个字段的值
总结hmget的用法 hmget key field [field ...] 一次获取hash中多个指定字段的值。返回值是对应字段的值或nil。
hlen获取hash中所有字段的个数
总结hlen的用法 hlen key获取hash中所有字段的个数返回值是字段的个数。 执行hlen命令是不用遍历的。
hincrby给hash中指定字段对应的值 加n(n是整数)
field-value中的value也可以当做数字来处理。
总结hincrby的用法 hincrby key field incrment给field对应的value 加上incrment。返回值是field的新值。
hincrbyfloat给hash中指定字段对应的值 加n(n是浮点数)
hincrbyfloat是hincrby的浮点数版本。
hash相关命令小结 其中hstrlen key field计算的是field-value中的value的长度。
hash内部编码
hash的内部编码有两种分别是ziplist(压缩列表)和hashtable(哈希表)。
压缩的本质是针对数据进行重新编码。 不同的数据有不同的特点结合这些特点进行精妙的设计(压缩算法)重新编码之后就能缩小体积。比如一个字符串abc0000000000000efg重新编码后字符串变成了abc13[13]efg。
zipllist内部的数据结构也是精心设计的相比于hashtable存储hash会存在浪费空间的问题redis内部用ziplist类型存储hash能节省内存空间。
ziplist的缺点读写元素时候速度较慢如果hash中元素个数少慢的不明显但是如果元素个数太多就很慢了。
所以如果哈希中的元素个数比较少使用ziplist存储如果hash中元素个数比较多使用hashtable来存储。 且如果field-value中value都比较短使用ziplist存储hash如果某个value的长度过长也会转换成hashtable存储hash。
通过修改redis配置文件redis.conf中的配置项hash-max-ziplist-entries(默认512个)确定hash中的元素个数超过多少时用hashtable存储hash。 通过修改redis配置文件redis.conf中的配置项hash-max-ziplist-value(默认64字节)确定hash中的元素长度超过多少时用hashtable存储hash。 hash的应用
作为缓存
redismysql组成的缓存存储架构 假设把最近使用到的数据作为热点数据存储在redis中 在上面的场景中 redis做缓存应用服务器访问数据先查询Redis如果redis上数据存在就直接从redis上取数据交给应用服务器不继续访问mysql了。如果redis上数据不存在再读取mysql把读到的结果返回给应用服务器的同时把这个数据也写入到redis中。
用伪代码模拟上述场景理解hash在其中的应用 redis用key-value组织用户信息 key是user:uidvalue是hash类型。 用mysql保存用户信息
//当用户发来请求时假设业务根据用户uid获取用户信息
//业务层
UserInfo getUserInfo(long uid){//先查询redis假设用户信息保存在user:uid对应的键中。String key user:uid;//从redis中获取对应的值UserInfoMap value redis命令hgetall key;//如果缓存命中(hit)if(value ! null){//将映射关系还原成对象形式UserInfo userInfo 利用映射关系构建对象UserInfoMap value;return userInfo;}//如果缓存没有命中(miss)//从数据库中根据uid获取用户信息UserInfo userInfo mysql执行sql语句select * from user_info where uid uid;//如果表中没有 uid 对应的⽤⼾信息if(userInfo null){响应404return null;}//将缓存以哈希类型保存redis执行命令hmset user:userInfo.uid name userInfo.name age userInfo.age city userInfo.city//写入缓存为了防止数据腐烂rot设置过期时间为1 ⼩时3600 秒redis执行命令expire user:userInfo.uid 3600//返回用户信息return userInfo;
}比较hash类型和关系型数据库存储用户信息的区别
哈希类型是稀疏的而关系型数据库是完全结构化的。例如哈希类型每个键可以有不同的field而关系型数据库⼀旦添加新的列所有行都要为其设置值即使为null。 关系数据库可以做复杂的关系查询而Redis去模拟关系型复杂查询例如联表查询、聚合查询等基本不可能维护成本高。
三种缓存方式对比 原生字符串类型⸺⸺使用字符串类型每个属性⼀个键。 优点实现简单针对个别属性变更也很灵活。 缺点占用过多的键内存占用量较⼤同时用户信息在Redis中比较分散缺少内聚性所以这种方案基本没有实⽤性。 序列化字符串类型例如JSON格式 优点针对总是以整体作为操作的信息比较合适编程也简单。同时如果序列化方案选择合适内存的使用效率很高。 缺点本⾝序列化和反序列需要⼀定开销同时如果总是操作个别属性则非常不灵活。 hash类型 优点简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。 缺点需要控制哈希在ziplist和hashtable两种内部编码的转换可能会造成内存的较大消耗。
比较redis用String类型(Json格式)和用hash类型存储用户信息的区别
如果用String(JSON)的格式来表示UserInfo从redis里取出的数据要先通过JSON反序列化转换成对象从mysql取出的数据要先通过JSON序列化转换成JSON格式。
但是如果用hash类型保存UserInfo就不用上面两个格外的步骤。且用field表示对象的每个属性还可以非常方便的修改/获取任何一个属性的值。 当然用hash类型保存UserInfo也有缺点使用hash类型需要控制hash在ziplist和hashtable两种内部编码的转换这可能会造成内存的较大消耗。(用空间换时间)
高内聚低耦合
内聚和耦合是衡量代码好坏的标准之一。好的代码应该是高内聚低耦合的。
高内聚内聚是用来衡量一个模块内部各个元素如函数、类的方法等之间的功能相关性和紧密程度的。高内聚意味着模块内的各个部分在功能上高度相关共同协作完成一个明确的任务。相反低内聚则表示模块内的各个部分功能不相关或关系松散。 比如上面提到的把一个用户的所有信息放到hash中一个key中就是高内聚代码。
低耦合耦合指的是两个代码/模块之间的关联关系好的代码追求的是低耦合。模块之间耦合度越高模块之间越容易相互影响。 比如在分布式系统中引入消息队列就是一个低耦合应用的例子 假设在一个分布式系统中A服务器直接调用B服务器A给B发送请求B处理请求返回响应给A此时A和B之间的耦合度是比较大的。 但如果在A和B之间引入消息队列此时A消息队列B三者构成生产者消费者模型A把请求发给消息队列B再从消息队列中获取请求这种情况下如果A出现问题牵连到B的可能性就很小A和B之间互连程度降低即降低了A和B之间的耦合度。 下次见~