Redis的Hash資料結構也是我很常使用的一種,
和c# 的HashTable、Dictionary很類似,
所以只要商業邏輯有需要使用Dictionary存放,
我都優先甚至第一考慮使用Hash。
前面我說過第一考慮使用Hash,這是因為Hash對記憶有優化(使用任何記憶體資料庫產品,你不得不在意記憶體優化),
優化程度取決於hash-max-ziplist-entries和hash-max-ziplist-value設定,
Hash在Redis內部可能是ziplist or a hash table,基本上被設計為高效能的雙向鏈結表(dually linked list),
且整數資料類型被真實儲存為整數而非字串。
但要注意一點,只要hash大小不超過hash-max-ziplist-entries設定,
基本上預設都採ziplist(ziplist對記憶體有優化),但搜尋時間卻不是一個常數,
而Hash table雖然沒有記憶體上的優化,但搜尋時間卻是一個常數。
由於透過string資料型別儲存其他屬性必須進行序列化和反序列化,
而且修改某一屬性必須把整個entity取回並lock對並發情況進行保護,
這時Hash就提供了很好的解決方法,假設今天要儲存使用者資訊,key依然是使用者ID,
但value是一個map,這個map的key是屬性名,value是屬性值,當要修改或存取內部的key,
可以透過key(使用者ID)+field(屬性名)操作對應屬性值,如此便可避免序列化、反序列化花費,
和併發修改控制的問題,但要注意map的屬性名不可過多,因為Redis為單一執行緒,map列舉過多可能會相當耗時。
下圖為Hash所有方法,但我這裡老樣子只示範CRUD。
StackExchangeRedisHelper _StackExchangeRedisHelper = new StackExchangeRedisHelper();
using (conn = _StackExchangeRedisHelper.SafeConn)
{
IDatabase _IDatabase = conn.GetDatabase();
var ricoID = "1";
HashEntry[] RicoUserInfoHash = {
new HashEntry("Name", "rico"),
new HashEntry("Birthday", "1982-01-01 11:11:00"),
new HashEntry("Sex", 1)
};
_IDatabase.HashSet(ricoID, RicoUserInfoHash);
var sherryID = "2";
HashEntry[] SherryUserInfoHash = {
new HashEntry("Name", "sherry"),
new HashEntry("Birthday", "1982-01-11 12:12:00"),
new HashEntry("Sex", 0)
};
_IDatabase.HashSet(sherryID, SherryUserInfoHash);
var ricoallHash = _IDatabase.HashGetAll(ricoID);//select all the properties
foreach (var item in ricoallHash)
{
Console.WriteLine(string.Format("key : {0}, value : {1}", item.Name, item.Value));
}
var sherryallHash = _IDatabase.HashGetAll(sherryID);//select all the properties
foreach (var item in sherryallHash)
{
Console.WriteLine(string.Format("key : {0}, value : {1}", item.Name, item.Value));
}
if (_IDatabase.HashExists(ricoID, "Name"))//判斷Name屬性是否存在
{
var name = _IDatabase.HashGet(ricoID, "Name"); //取得Name屬性值
Console.WriteLine("UserID:{0} , Name:{1}", ricoID.ToString(), name.ToString());
_IDatabase.HashSet(ricoID, "Name", "ricoisme", When.Always, CommandFlags.FireAndForget);//Always update
name = _IDatabase.HashGet(ricoID, "Name"); //取得Name屬性值
Console.WriteLine("UserID:{0} , Name:{1}", ricoID.ToString(), name.ToString());
}
//get all the values
var values = _IDatabase.HashValues(ricoID);
foreach (var val in values)
{
Console.WriteLine(val);
}
//get all the keys
var keys = _IDatabase.HashKeys(ricoID);
foreach (var key in keys)
{
Console.WriteLine(key);
}
var HashLength = _IDatabase.HashLength(ricoID);
Console.WriteLine("HashLength:{0}", HashLength.ToString());
_IDatabase.HashDelete(sherryID, "Birthday", CommandFlags.FireAndForget);//刪除 Birthday 屬性
if (!_IDatabase.HashExists(sherryID, "Birthday"))//判斷Birthday屬性是否存在
{
Console.WriteLine("UserID:{0} ,Birthday屬性 不存在", sherryID.ToString());
}
}
參考