玩轉redis —— 第4篇 雜湊物件型別
redis中的hash也是我們使用中的高頻資料結構, 它的構造基本上和程式語言中的HashTable,Dictionary大同小異,
如果大家往後有什麼邏
輯需要用
Dictionary存放的話, 可以根據場景優先考慮下redis哦, 起碼可以裝裝逼嘛, 現在我預設你已經有裝逼的衝動了, 開啟redis手冊,
看看有哪些我們
用得到
的裝逼方法。
一: 常用方法
只要是一個數據結構,最基礎的永遠是CURD,redis中的insert和update,永遠只會需要set來替代,比如下面的Hset,如下圖:
前面幾篇文章我都沒有挑選一個方法仔細講解, 其實也沒什麼好講解的, 就好似C#中的一個類的一個方法而已, 知道傳遞一些啥引數就
如要
說的HSet, 它的格式如下:
HSET key field value
將雜湊表 key 中的域field 的值設為 value 。
如果 key 不存在,一個新的雜湊表被建立並進行HSET 操作。
如果域 field 已經存在於雜湊表中,舊值將被覆蓋。
- 可用版本:
- >= 2.0.0
- 時間複雜度:
- O(1)
- 返回值:
- 如果 field 是雜湊表中的一個新建域,並且值設定成功,返回1 。 如果雜湊表中域 field 已經存在且舊值已被新值覆蓋,返回 0 。
redis> HSET website google "www.g.cn" # 設定一個新域 (integer) 1 redis> HSET website google "www.google.com" # 覆蓋一箇舊域 (integer) 0接下來我在CentOS裡面操作一下
前提是連線上redis
在資料夾中的執行:src/redis-cli
或許有人看了上面的console有一點疑惑, 那就是前面有幾個引數, 比如person,name啦,
然後才是value, 如果你看了第一篇的話, 你大概就明
白了,
其實在redis的這個層面, 它永遠只有一個鍵, 一個值, 這個鍵永遠都是字串物件, 也就是SDS物件, 而值的種類就多了, 有字串物件, 有佇列
物件,
還有這篇的hash物件, 往後的有序集合物件等等, 如果你還不明白的話, 轉化為C#語言就是。
呼叫方法就是這麼的簡單, 關鍵在於時不時的需要你看一看手冊, 其實最重要的是瞭解下它在
二: 探索原理
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的原始碼資料結構, 接下來我來擼一擼其中的邏輯關係。
1. dict結構
typedef struct dict {
2 dictType *type;
3 void *privdata;
4 dictht ht[2];
5 long rehashidx; /* rehashing not in progress if rehashidx == -1 */
6 int iterators; /* number of iterators currently running */
7 } dict;
這個結構是hash的真正的底層資料結構, 可以看到其中有5個屬性。
<1> dictType *type
可以看到它的型別是dictType, 從上面你也可以看到, 它是有列舉結構定義的, 如下:
typedef struct dictType {
2 unsigned int (*hashFunction)(const void *key);
3 void *(*keyDup)(void *privdata, const void *key);
4 void *(*valDup)(void *privdata, const void *obj);
5 int (*keyCompare)(void *privdata, const void *key1, const void *key2);
6 void (*keyDestructor)(void *privdata, void *key);
7 void (*valDestructor)(void *privdata, void *obj);
8 } dictType;
從上面這個資料結構中你可以看到裡面都是一些方法, 但是有一個非常重要的方法, 那就是第一個hashFunction, 可以看到它就是計算hash值
的,
跟C#中的dictionary中求hash值一樣一樣的。
<2> dictht ht[2]
你可能會疑問, 為什麼這個屬性是2個大小的陣列呢, 其實正真使用的是ht[0], 而ht[1]是用於擴容hash表時的暫存陣列,
這一點也很奇葩,
同時也很精妙, redis為什麼會這麼做呢? ? ? 仔細想想你可能會明白, 擴容有兩種方法, 要麼一次性擴容, 要麼漸進性擴容, 後面這種擴容是什
麼意思呢? 就是我在擴容的同時不影響前端的CURD, 我慢慢的把資料從ht[0]轉移到ht[1]中,
同時rehashindex來記錄轉移的情況, 當全部轉移
完成之後, 將ht[1]改成ht[0]使用, 就這麼簡單。
2. dicth結構
typedef struct dictht {
2 dictEntry **table;
3 unsigned long size;
4 unsigned long sizemask;
5 unsigned long used;
6 } dictht;
<1> dictEntry **table;
從上面這個結構體中, 你可以看到一個非常重要的屬性: dictEntry **table, 其中table是一個數組, 陣列型別是dictEntry, 既然是一個
陣列,
那後面的三個屬性就好理解了, size是陣列的大小,sizemask和陣列求模有關,used記錄陣列中已使用的大小, 現在我們把注意力放在dictEntry
這 個
陣列實體型別上面。
3. dictEntry結構
typedef struct dictEntry {2 void *key;
3 union {
4 void *val;
5 uint64_t u64;
6 int64_t s64;
7 double d;
8 } v;
9 struct dictEntry *next;
10 } dictEntry;
從這個資料結構上面你可以看到有三個大屬性。
第一個就是: *key: 它就是hash表中的key。
第二個就是: union的*val就是hash的value。
第三個就是: *next就是為了防止hash衝突採用的掛鏈手段。
這個原理和C#中的Dictionary還是一樣一樣的。
不知道你看懂了沒有, 如果總結上面描述的話, 我可以畫出如下的hash結構圖。
相關推薦
玩轉redis —— 第4篇 雜湊物件型別
redis中的hash也是我們使用中的高頻資料結構, 它的構造基本上和程式語言中的HashTable,Dictionary大同小異, 如果大家往後有什麼邏 輯需要用Dictionary存放的話, 可
15天玩轉redis —— 第三篇 無敵的列表型別
據說60%的人使用redis看重的是redis中的list型別,那這個list有什麼用呢???不用我說大家都明白,做佇列使用唄,為什麼用它呢,很簡單唄, 因為有了它我就不需要專門的MQ產品啦,比如說RabbitMQ,ActiveMQ等等。。。對吧。 一:實戰 先
15天玩轉redis —— 第五篇 集合物件型別
1 /* 2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 3 * All rights reserved. 4 * 5 * Redistribution and
15天玩轉redis —— 第十篇 對快照模式的深入分析
我們知道redis是帶有持久化這個能力了,那到底持久化成到哪裡,持久化成啥樣呢???這篇我們一起來尋求答案。 一:快照模式 或許在用Redis之初的時候,就聽說過redis有兩種持久化模式,第一種是SNAPSHOTTING模式,還是一種是AOF模式,而且在實
15天玩轉redis —— 第九篇 釋出/訂閱模式
本系列已經過半了,這一篇我們來看看redis好玩的釋出訂閱模式,其實在很多的MQ產品中都存在這樣的一個模式,我們常聽到的一個例子 就是郵件訂閱的場景,什麼意思呢,也就是說100個人訂閱了你的部落格,如果博主發表了文章,那麼100個人就會同時收到通知郵件,除了這個 場景還能找到
redis 第 4 篇 Redis資料型別----string
命令 賦值 語法:SET key value 127.0.0.1:6379> set test 123 OK 取值 語法:GET key 127.0.0.1:6379> ge
支撐微博億級社交平臺,小白也能玩轉Redis叢集(原理篇)
Redis作為一款效能優異的記憶體資料庫,支撐著微博億級社交平臺,也成為很多網際網路公司的標配。這裡將以Redis Cluster叢集為核心,基於最新的Redis5版本,從原理再到實戰,玩轉Redis叢集 常見Redis叢集方案 在介紹Redis Cluster叢集方案之前,為了方便對比,先簡單瞭解一下業
支撐微博億級社交平臺,小白也能玩轉Redis叢集(實戰篇)
上篇文章《支撐微博億級社交平臺,小白也能玩轉Redis叢集(原理篇)》介紹了Redis叢集相關原理,這篇文章將介紹Redis Cluster叢集的搭建、配置,運維、擴容等具體操作 叢集搭建 2018年10月 Redis 釋出了穩定版本的 5.0 版本,推出了各種新特性,其中一點是叢集管理工具從基於Ruby
《Python學習手冊》學習筆記(4)之第4章介紹Python物件型別(關鍵詞:程式語言/Python)
第4章 介紹Python物件型別 寫在開頭的讀者筆記 值得一讀的小節 1.“為什麼使用內建型別” - “Python的核心資料型別”,主要學到了: Python是強型別語言,你只能對一個物件進行適合該型別的有效操作。 一旦建立了一個物件,它就和
【轉】Node深入淺出 章節總結(第九章 — 玩轉程序) 完結篇
為了看黑色背景,就轉了過來,眼睛看白色螢幕實在受不鳥! 本章總結將結合個人搭建 egg 引入公司的一些實踐來進行總結,希望能讓大家瞭解到程序管理和叢集分發的重要性。 閱讀完本章你應該理解以下幾點: 為什麼要使用多程序架構啟動服務; 經典的 Master-Worker
15天玩轉redis —— 第一篇 開始入手
雙十一終於還是過去了,我負責的mongodb由於做了副本集,最終還是挺過去了,同事負責的redis,還是遺憾的在早上8點左右宕機了,然後大家就是馬不停 蹄的趕往公司解決問題,因為我對redis也不是很瞭解,工作上使用redis的時候也是應付的找找資料,所以沒有從系統層
玩轉redis持久化,阿里架構師給你來一篇方案介紹
一、基本介紹 本次演示使用的redis版本是3.2.100,作業系統是win10。 redis支援兩種持久化方案,RDB和AOF
老司機帶你玩轉面試(4):Redis 高可用之哨兵模式
![](https://cdn.geekdigging.com/Interview/mianshi_header_1.jpg) ## 前文回顧 建議前面文章沒看過的同學先看下前面的文章: [「老司機帶你玩轉面試(1):快取中介軟體 Redis 基礎知識以及資料持久化」](https://www.geek
第4篇-JAVA基礎
關鍵字 continue 表達式 java基礎 布爾 第4篇-JAVA基礎每篇一句 :世界上本沒有完美,但是我們從未放棄追求完美初學心得: 樂於揮霍的時間,都不能算作浪費(筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-01| JAVA基礎 Ⅳ]程序運行流程(1) 順序結
HTTP跳轉HTTPS第三篇
p s write 測試 直接 list 域名跳轉 mil /var/ star 一、實現訪問http跳轉https訪問(http的單向認證)①修改配置文件# vim /etc/httpd/conf/httpd.conf 增加在文件最後 <IfModule s
Python學習【第4篇】:元組魔法
vaule 根據 取值 保留 列表 tuple 樣書 key值 推薦 tu = (111,"xiaoxing",(11,22),[(33,44)],45,)#1.書寫格式#一般寫元組的時候推薦在最後加入逗號,#元組中的一級元素不可被修改,不能增加或者刪除print(tu)#
開啟運維之路之第 4 篇——常見軟體安裝:JRE、MySQL、Tomcat安裝
1、JRE安裝:在正式環境裡 我們可以不安裝jdk ,僅僅安裝Java執行環境 jre即可。 ①下載jre:JRE官網下載地址 開啟連結,勾選協議,下載Linux版本64位的 ②上傳jre到/home/data/下:使用FTP工具上傳。 如果上傳過程遇到下面的問題:連線到
第八章雜湊
雜湊的含義 散列表(Hash table,也叫雜湊表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。 對不同的關鍵字可能得到同一雜湊地址,即k1≠k2,
玩轉 Redis 叢集之 Sentinel
Redis作為記憶體資料庫,需要具備高可用的特點,不然如果伺服器宕機,還在記憶體裡的資料就會丟失。我們最常用的高可用方法就是搭建叢集,master機器掛了,可以讓slave機器頂上,繼續提供服務。但是Redis叢集是不會自動進行主從切換的,也就是說,如果主節點非常不爭氣的在凌晨3點掛了,那麼運維同學就
玩轉Redis叢集之Sentinel
Redis作為記憶體資料庫,需要具備高可用的特點,不然如果伺服器宕機,還在記憶體裡的資料就會丟失。我們最常用的高可用方法就是搭建叢集,master機器掛了,可以讓slave機器頂上,繼續提供服務。但是Redis叢集是不會自動進行主從切換的,也就是說,如果主節點非常不爭氣的在凌晨3點掛了,那麼運維同學就要馬上起