15天玩转redis —— 第四篇 哈希对象类型
redis中的hash也是我们使用中的高频数据结构,它的构造基本上和编程语言中的HashTable,Dictionary大同小异,如果大家往后有什么逻辑需要用 Dictionary存放的话,可以根据场景优先考虑下redis哦,起码可以装装逼嘛,现在我默认你已经有装逼的冲动了,打开redis手册,看看有哪些我们用得到 的装逼方法。
只要是一个数据结构,最基础的永远是CURD,redis中的insert和update,永远只需要set来替代,比如下面的Hset,如下图: 前面几篇文章我都没有挑选一个方法仔细讲解,其实也没什么好讲解的,就好似C#中的一个类的一个方法而已,知道传递一些啥参数就OK了,就比如要 说的HSet,它的格式如下: 接下来我在CentOS里面操作一下, [administrator@localhost redis-.]$ src/redis-.:><span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379><span style="color: #000000;"><span style="color: #ff0000;"> hset person name jack
(integer) <span style="color: #800080;">1 <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379> <span style="color: #ff0000;">hset person age <span style="color: #800080;">20<span style="color: #000000;"> (integer) <span style="color: #800080;">1 <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379><span style="color: #000000;"><span style="color: #ff0000;"> hset person sex famale (integer) <span style="color: #800080;">1 <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379><span style="color: #000000;"><span style="color: #ff0000;"> hgetall person <span style="color: #800080;">1) <span style="color: #800000;">"<span style="color: #800000;">name<span style="color: #800000;">" <span style="color: #800080;">2) <span style="color: #800000;">"<span style="color: #800000;">jack<span style="color: #800000;">" <span style="color: #800080;">3) <span style="color: #800000;">"<span style="color: #800000;">age<span style="color: #800000;">" <span style="color: #800080;">4) <span style="color: #800000;">"<span style="color: #800000;">20<span style="color: #800000;">" <span style="color: #800080;">5) <span style="color: #800000;">"<span style="color: #800000;">sex<span style="color: #800000;">" <span style="color: #800080;">6) <span style="color: #800000;">"<span style="color: #800000;">famale<span style="color: #800000;">" <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379><span style="color: #000000;"><span style="color: #ff0000;"> hkeys person <span style="color: #800080;">1) <span style="color: #800000;">"<span style="color: #800000;">name<span style="color: #800000;">" <span style="color: #800080;">2) <span style="color: #800000;">"<span style="color: #800000;">age<span style="color: #800000;">" <span style="color: #800080;">3) <span style="color: #800000;">"<span style="color: #800000;">sex<span style="color: #800000;">" <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379><span style="color: #000000;"><span style="color: #ff0000;"> hvals person <span style="color: #800080;">1) <span style="color: #800000;">"<span style="color: #800000;">jack<span style="color: #800000;">" <span style="color: #800080;">2) <span style="color: #800000;">"<span style="color: #800000;">20<span style="color: #800000;">" <span style="color: #800080;">3) <span style="color: #800000;">"<span style="color: #800000;">famale<span style="color: #800000;">" <span style="color: #800080;">127.0.<span style="color: #800080;">0.1:<span style="color: #800080;">6379> 或许有人看了上面的console有一点疑惑,那就是前面有几个参数,比如person,name啦,然后才是value,如果你看了第一篇的话,你大概就明白了, 其实在redis的这个层面,它永远只有一个键,一个值,这个键永远都是字符串对象,也就是SDS对象,而值的种类就多了,有字符串对象,有队列对象, 还有这篇的hash对象,往后的有序集合对象等等,如果你还不明白的话,转化为C#语言就是。 person= Dictionary<,> person.Add(, ....
调用方法就是这么的简单,关键在于时不时的需要你看一看手册,其实最重要的是了解下它在redis源码中的原理就好了。
hash的源代码是在dict.h源代码里面,枚举如下: typedef * * dictEntry *typedef <span style="color: #0000ff;">struct<span style="color: #000000;"> dictType {
unsigned <span style="color: #0000ff;">int (hashFunction)(<span style="color: #0000ff;">const <span style="color: #0000ff;">void <span style="color: #000000;">key); <span style="color: #0000ff;">void (keyDup)(<span style="color: #0000ff;">void privdata,<span style="color: #0000ff;">const <span style="color: #0000ff;">void <span style="color: #000000;">key); <span style="color: #0000ff;">void (valDup)(<span style="color: #0000ff;">void privdata,<span style="color: #0000ff;">const <span style="color: #0000ff;">void <span style="color: #000000;">obj); <span style="color: #0000ff;">int (keyCompare)(<span style="color: #0000ff;">void privdata,<span style="color: #0000ff;">const <span style="color: #0000ff;">void key1,<span style="color: #0000ff;">const <span style="color: #0000ff;">void <span style="color: #000000;">key2); <span style="color: #0000ff;">void (keyDestructor)(<span style="color: #0000ff;">void privdata,<span style="color: #0000ff;">void <span style="color: #000000;">key); <span style="color: #0000ff;">void (valDestructor)(<span style="color: #0000ff;">void privdata,<span style="color: #0000ff;">void <span style="color: #000000;">obj); } dictType; <span style="color: #008000;">/*<span style="color: #008000;"> This is our hash table structure. Every dictionary has two of this as we
typedef <span style="color: #0000ff;">struct<span style="color: #000000;"> dict { <span style="color: #008000;">/*<span style="color: #008000;"> If safe is set to 1 this is a safe iterator,that means,you can call
上面就是我们使用hash的源代码数据结构,接下来我来撸一撸其中的逻辑关系。
typedef dictType * * dictht ht[ rehashidx;
iterators;
} dict;
这个结构是hash的真正的底层数据结构,可以看到其中有5个属性。 ?dictType *type 可以看到它的类型是dictType,从上面你也可以看到,它是有枚举结构定义的,如下: typedef unsigned (*hashFunction)( * *(*keyDup)( *privdata, * *(*valDup)( *privdata, * (*keyCompare)( *privdata, * (*keyDestructor)( *privdata, * (*valDestructor)( *privdata, * } dictType;
从上面这个数据结构中你可以看到里面都是一些方法,但是有一个非常重要的方法,那就是第一个hashFunction,可以看到它就是计算hash值的, 跟C#中的dictionary中求hash值一样一样的。 ?dictht ht[2] ? ? ? ?你可能会疑问,为什么这个属性是2个大小的数组呢,其实正真使用的是ht[0],而ht[1]是用于扩容hash表时的暂存数组,这一点也很奇葩, 同时也很精妙,redis为什么会这么做呢???仔细想想你可能会明白,扩容有两种方法,要么一次性扩容,要么渐进性扩容,后面这种扩容是什 么意思呢?就是我在扩容的同时不影响前端的CURD,我慢慢的把数据从ht[0]转移到ht[1]中,同时rehashindex来记录转移的情况,当全部转移 完成之后,将ht[1]改成ht[0]使用,就这么简单。
typedef unsigned unsigned unsigned } dictht;
?dictEntry **table; ? ? ? ?从上面这个结构体中,你可以看到一个非常重要的属性:?dictEntry **table, 其中table是一个数组,数组类型是dictEntry,既然是一个数组, 那后面的三个属性就好理解了,size是数组的大小,sizemask和数组求模有关,used记录数组中已使用的大小,现在我们把注意力放在dictEntry这 个数组实体类型上面。
typedef * * dictEntry * } dictEntry;
从这个数据结构上面你可以看到有三个大属性。 第一个就是: ? *key:它就是hash表中的key。 第二个就是: ? ?union的*val 就是hash的value。 第三个就是: ? ?*next就是为了防止hash冲突采用的挂链手段。 这个原理和C#中的Dictionary还是一样一样的。 不知道你看懂了没有,如果总结上面描述的话,我可以画出如下的hash结构图。 好了,就此打住,去公司了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |