redis哈希類型_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
redis中的hash也是我們使用中的高頻數(shù)據(jù)結(jié)構(gòu),它的構(gòu)造基本上和編程語(yǔ)言中的HashTable,Dictionary大同小異,如果大家往后有什么邏輯需要用Dictionary存放的話,可以根據(jù)場(chǎng)景優(yōu)先考慮下redis哦。
一:常用方法
只要是一個(gè)數(shù)據(jù)結(jié)構(gòu),最基礎(chǔ)的永遠(yuǎn)是CURD,redis中的insert和update,永遠(yuǎn)只需要set來(lái)替代,比如下面的Hset,如下圖:
就好像Java中的類和方法,知道傳遞一些啥參數(shù)就OK了,就比如要說(shuō)的HSet,它的格式如下:
接下來(lái)我在CentOS里面操作一下,
[administrator@localhost redis-3.0.5]$ src/redis-cli .0.0.1:6379> clear .0.0.1:6379> hset person name jack (integer) 1 .0.0.1:6379> hset person age 20 (integer) 1 .0.0.1:6379> hset person sex famale (integer) 1 .0.0.1:6379> hgetall person ) "name" ) "jack" ) "age" ) "20" ) "sex" ) "famale" .0.0.1:6379> hkeys person ) "name" ) "age" ) "sex" .0.0.1:6379> hvals person ) "jack" ) "20" ) "famale" .0.0.1:6379>
或許有人看了上面的console有一點(diǎn)疑惑,那就是前面有幾個(gè)參數(shù),比如person,name啦,然后才是value,其實(shí)在redis的這個(gè)層面,它永遠(yuǎn)只有一個(gè)鍵,一個(gè)值,這個(gè)鍵永遠(yuǎn)都是字符串對(duì)象,也就是SDS對(duì)象,而值的種類就多了,有字符串對(duì)象,有隊(duì)列對(duì)象,還有這篇的hash對(duì)象,往后的有序集合對(duì)象等等,如果你還不明白的話,轉(zhuǎn)化為Java語(yǔ)言就是。
Map<String,String> person=new HashMap<string,string>(); person.Add("name","jack"); ....
調(diào)用方法就是這么的簡(jiǎn)單,關(guān)鍵在于時(shí)不時(shí)的需要你看一看手冊(cè),其實(shí)最重要的是了解下它在redis源碼中的原理就好了。
二:探索原理
hash的源代碼是在dict.h源代碼里面,枚舉如下:
typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next; } dictEntry; typedef struct dictType { unsigned int (*hashFunction)(const void *key); void *(*keyDup)(void *privdata, const void *key); void *(*valDup)(void *privdata, const void *obj); int (*keyCompare)(void *privdata, const void *key1, const void *key2); void (*keyDestructor)(void *privdata, void *key); void (*valDestructor)(void *privdata, void *obj); } dictType; /* This is our hash table structure. Every dictionary has two of this as we * implement incremental rehashing, for the old to the new 0. */ typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used; } dictht; typedef struct dict { dictType *type; void *privdata; dictht ht[2]; long rehashidx; /* rehashing not in progress if rehashidx == -1 */ int iterators; /* number of iterators currently running */ } dict; /* If safe is set to 1 this is a safe iterator, that means, you can call * dictAdd, dictFind, and other functions against the dictionary even while * iterating. Otherwise it is a non safe iterator, and only dictNext() * should be called while iterating. */ typedef struct dictIterator { dict *d; long index; int table, safe; dictEntry *entry, *nextEntry; /* unsafe iterator fingerprint for misuse detection. */ long long fingerprint; } dictIterator;
上面就是我們使用hash的源代碼數(shù)據(jù)結(jié)構(gòu),接下來(lái)我來(lái)擼一擼其中的邏輯關(guān)系。
dict結(jié)構(gòu)
typedef struct dict { dictType *type; void *privdata; dictht ht[2]; long rehashidx; /* rehashing not in progress if rehashidx == -1 */ int iterators; /* number of iterators currently running */ } dict;
這個(gè)結(jié)構(gòu)是hash的真正的底層數(shù)據(jù)結(jié)構(gòu),可以看到其中有5個(gè)屬性。
<1> dictType *type
可以看到它的類型是dictType,從上面你也可以看到,它是有枚舉結(jié)構(gòu)定義的,如下:
typedef struct dictType { unsigned int (*hashFunction)(const void *key); void *(*keyDup)(void *privdata, const void *key); void *(*valDup)(void *privdata, const void *obj); int (*keyCompare)(void *privdata, const void *key1, const void *key2); void (*keyDestructor)(void *privdata, void *key); void (*valDestructor)(void *privdata, void *obj); } dictType;
從上面這個(gè)數(shù)據(jù)結(jié)構(gòu)中你可以看到里面都是一些方法,但是有一個(gè)非常重要的方法,那就是第一個(gè)hashFunction,可以看到它就是計(jì)算hash值的,跟Java中的求hash值差不多。
<2> dictht ht[2]
你可能會(huì)疑問(wèn),為什么這個(gè)屬性是2個(gè)大小的數(shù)組呢,其實(shí)正真使用的是ht[0],而ht[1]是用于擴(kuò)容hash表時(shí)的暫存數(shù)組,這一點(diǎn)也很奇葩,同時(shí)也很精妙,redis為什么會(huì)這么做呢???仔細(xì)想想你可能會(huì)明白,擴(kuò)容有兩種方法,要么一次性擴(kuò)容,要么漸進(jìn)性擴(kuò)容,后面這種擴(kuò)容是什么意思呢?就是我在擴(kuò)容的同時(shí)不影響前端的CURD,我慢慢的把數(shù)據(jù)從ht[0]轉(zhuǎn)移到ht[1]中,同時(shí)rehashindex來(lái)記錄轉(zhuǎn)移的情況,當(dāng)全部轉(zhuǎn)移完成之后,將ht[1]改成ht[0]使用,就這么簡(jiǎn)單。
dicth結(jié)構(gòu)
typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used; } dictht;
<1> dictEntry **table;
從上面這個(gè)結(jié)構(gòu)體中,你可以看到一個(gè)非常重要的屬性: dictEntry **table, 其中table是一個(gè)數(shù)組,數(shù)組類型是dictEntry,既然是一個(gè)數(shù)組,那后面的三個(gè)屬性就好理解了,size是數(shù)組的大小,sizemask和數(shù)組求模有關(guān),used記錄數(shù)組中已使用的大小,現(xiàn)在我們把注意力放在dictEntry這個(gè)數(shù)組實(shí)體類型上面。
dictEntry結(jié)構(gòu)
typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next; } dictEntry;
從這個(gè)數(shù)據(jù)結(jié)構(gòu)上面你可以看到有三個(gè)大屬性。
第一個(gè)就是: *key:它就是hash表中的key。
第二個(gè)就是: union的*val 就是hash的value。
第三個(gè)就是: *next就是為了防止hash沖突采用的掛鏈?zhǔn)侄巍?nbsp;
如果總結(jié)上面描述的話,我可以畫出如下的hash結(jié)構(gòu)圖。
相關(guān)文章
redis.conf中使用requirepass不生效的原因及解決方法
本文主要介紹了如何啟用requirepass,以及啟用requirepass為什么不會(huì)生效,從代碼層面分析了不生效的原因,以及解決方法,需要的朋友可以參考下2023-07-07Redis批量生成數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了Redis批量生成數(shù)據(jù)的實(shí)現(xiàn),主要介紹了兩種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06淺談redis的maxmemory設(shè)置以及淘汰策略
下面小編就為大家?guī)?lái)一篇淺談redis的maxmemory設(shè)置以及淘汰策略。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03Redis?RESP?協(xié)議實(shí)現(xiàn)實(shí)例詳解
這篇文章主要為大家介紹了Redis?RESP?協(xié)議實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09生產(chǎn)redisson延時(shí)隊(duì)列不消費(fèi)問(wèn)題排查解決
這篇文章主要為大家介紹了生產(chǎn)redisson延時(shí)隊(duì)列不消費(fèi)問(wèn)題排查解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09redis key命名規(guī)范的設(shè)計(jì)
如果結(jié)構(gòu)規(guī)劃不合理、命令使用不規(guī)范,會(huì)造成系統(tǒng)性能達(dá)到瓶頸、活動(dòng)高峰系統(tǒng)可用性下降,也會(huì)增大運(yùn)維難度,本文主要介紹了redis key命名規(guī)范的設(shè)計(jì),感興趣的可以了解一下2024-03-03Python的Flask框架使用Redis做數(shù)據(jù)緩存的配置方法
Redis數(shù)據(jù)庫(kù)依賴于主存,在關(guān)系型數(shù)據(jù)庫(kù)以外再配套R(shí)edis管理緩存數(shù)據(jù)將對(duì)性能會(huì)有很大的提升,這里我們就來(lái)看一下Python的Flask框架使用Redis做數(shù)據(jù)緩存的配置方法2016-06-06