1. 程式人生 > >StackExchange.Redis學習筆記(二) Redis查詢 五種數據類型的應用

StackExchange.Redis學習筆記(二) Redis查詢 五種數據類型的應用

exchange redis 利用 用法 multipl database 評論 add and

原文:StackExchange.Redis學習筆記(二) Redis查詢 五種數據類型的應用

ConnectionMultiplexer

ConnectionMultiplexer 是StackExchange.Redis的核心對象,用這個類的實例來進行Redis的一系列操作,對於一個整個應用程序應該只有一個ConnectionMultiplexer 類的實例。上一章中StackExchangeRedisHelper 的相關代碼如下

  private static ConnectionMultiplexer _instance = null;
        /// <summary>
/// 使用一個靜態屬性來返回已連接的實例,如下列中所示。這樣,一旦 ConnectionMultiplexer 斷開連接,便可以初始化新的連接實例。 /// </summary> public static ConnectionMultiplexer Instance { get { if (_instance == null) { lock (_locker) {
if (_instance == null || !_instance.IsConnected) { _instance = ConnectionMultiplexer.Connect(Coonstr); } } } //註冊如下事件 _instance.ConnectionFailed += MuxerConnectionFailed; _instance.ConnectionRestored
+= MuxerConnectionRestored; _instance.ErrorMessage += MuxerErrorMessage; _instance.ConfigurationChanged += MuxerConfigurationChanged; _instance.HashSlotMoved += MuxerHashSlotMoved; _instance.InternalError += MuxerInternalError; return _instance; } }

String

 string類型應該是最長用到的了,用法也很簡單,下面展示了用Redis來進行基本的字符串數字存儲

 public static IDatabase GetDatabase()
        {
            return Instance.GetDatabase();
        }
        /// <summary>
        /// 設置緩存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void Set(string key, object value, TimeSpan? expiry = default(TimeSpan?), When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            key = MergeKey(key);
            GetDatabase().StringSet(key, Serialize(value), expiry, when, flags);
        }    
        /// <summary>
        /// 根據key獲取緩存對象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T Get<T>(string key)
        {
            key = MergeKey(key);
            return Deserialize<T>(GetDatabase().StringGet(key));
        }    
         /// <summary>
        /// 移除指定key的緩存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool Remove(string key)
        {
            key = MergeKey(key);
            return GetDatabase().KeyDelete(key);
        }    

除了基本的string類型操作,Redis同時支持以下幾種類型的操作

  • List 列表
  • Set 無序集合
  • SortedSet 有序集合
  • Hash 哈希表

下面我依次來介紹下這四種類型在StackExchange.Redis中的基本用法

關於代碼中的KeyDelete為刪除對應的鍵,我這裏是因為測試防止重復才加上的。大家不要誤會

List

  • 特點:有序排列,值可以重復。我們可以通過pop,push操作來從頭部和尾部刪除或者添加元素。這使得list既可以做棧也可以做隊列
  • 需求:要求一條微博將最新的10條評論用戶名字直接顯示在主頁上
  • 實現:
 public static void LatestUserTop10()
        {
            IDatabase db = StackExchangeRedisHelper.GetDatabase();
            //模擬有一百名用戶
            for (int i = 1; i <= 100; i++)   
            {
                db.ListLeftPush("user", "用戶"+i);
                //每一名用戶插入後都只保留最後的十個用戶到redis數據庫中
                db.ListTrim("user", 0, 9);
            }
            RedisValue[] userStores = db.ListRange("user");
            foreach (var item in userStores)
            {
                Console.Write((string)item + ",");
            }
            db.KeyDelete("user");
            Console.ReadLine();
        }

Set

  • 特點:無序排列,值不可重復。增加刪除查詢都很快。提供了取並集交集差集等一些有用的操作
  • 需求:取兩篇文章的評論者的交集並集差集
  • 實現:
 public void RedisSetTest()
        {
            IDatabase db = StackExchangeRedisHelper.GetDatabase();

            for (int i = 1; i <= 20; i++)
            {
                db.SetAdd("文章1", i);
            }
            for (int i = 15; i <= 35; i++)
            {
                db.SetAdd("文章2", i);
            }
            RedisValue[] inter = db.SetCombine(SetOperation.Intersect, "文章1", "文章2");
            RedisValue[] union = db.SetCombine(SetOperation.Union, "文章1", "文章2");
            RedisValue[] dif1 = db.SetCombine(SetOperation.Difference, "文章1", "文章2");
            RedisValue[] dif2 = db.SetCombine(SetOperation.Difference, "文章2", "文章1");
            int x = 0;
            Console.WriteLine("兩篇文章都評論過的用戶");
            foreach (var item in inter.OrderBy(m => m).ToList())
            {
                Console.Write((string)item + "  ");
            }
            Console.WriteLine("\n評論過兩篇文章中任意一篇文章的用戶");
            foreach (var item in union.OrderBy(m => m).ToList())
            {
                Console.Write((string)item + "  ");
            }
            Console.WriteLine("\n只評論過其第一篇文章的用戶");
            foreach (var item in dif1.OrderBy(m => m).ToList())
            {
                Console.Write((string)item + "  ");
            }
            Console.WriteLine("\n只評論過其第二篇文章的用戶");
            foreach (var item in dif2.OrderBy(m => m).ToList())
            {
                Console.Write((string)item + "  ");
            }
            db.KeyDelete("文章1");
            db.KeyDelete("文章2");
            Console.ReadLine();
        }

技術分享圖片

SortedSet

  • 特點:有序排列,值不可重復。類似Set,不同的是sortedset的每個元素都會關聯一個double類型的score,用此元素來進行排序
  • 需求:顯示文章被贊最多的十條評論
  • 實現:
public void HotestUserTop10()
        {
            IDatabase db = StackExchangeRedisHelper.GetDatabase();
            //模擬有一百名評論者,開始每個用戶被“贊”的次數為1
            List<SortedSetEntry> entrys = new List<SortedSetEntry>();
            for (int i = 1; i <= 100; i++)
            {
                db.SortedSetAdd("文章1", "評論者" + i, 1);
            }
            //評論者2又被贊了兩次
            db.SortedSetIncrement("文章1", "評論者2", 2); //對應的值的score+2
            //評論者101被贊了4次
            db.SortedSetIncrement("文章1", "評論者101", 4);  //若不存在該值,則插入一個新的
            RedisValue[] userStores = db.SortedSetRangeByRank("文章1", 0, 10, Order.Descending);
            for (int i = 0; i < userStores.Length; i++)
            {
                Console.WriteLine(userStores[i]+":"+ db.SortedSetScore("文章1", userStores[i]));
            }
            db.KeyDelete("文章1");
            Console.ReadLine();
        }

技術分享圖片

Hash

  • 特點:Hash是一個string類型的field和value的對應表,它更適合來存儲對象,相比於每個屬性進行一次緩存,利用hash來存儲整個對象會占用更小的內存。但是存儲速度並不會更快
  • 需求:存儲一個學生的基本信息
  • 實現:
  public void RedisHashTest()
        {
            IDatabase db = StackExchangeRedisHelper.GetDatabase();
            db.HashSet("student1", "name", "張三");
            db.HashSet("student1", "age", 12);
            db.HashSet("student1", "class", "五年級");
            Console.WriteLine(db.HashGet("student1", "name"));
            RedisValue[] result = db.HashGet("student1", new RedisValue[] { "name", "age","class" });
            Console.WriteLine(string.Join(",",result));
            db.KeyDelete("student1");
            Console.ReadLine();
        }

技術分享圖片

以下代碼是我分別用stringset和hash來存儲對象進行的時間及內存比較,內存可通過redis的info命令來查看。

最終顯示耗時方面stringset稍微快一點點,內存占用stringset卻是hash的二倍

 public void RedisHashVsStringSet()
        {
            IDatabase db = StackExchangeRedisHelper.GetDatabase();
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //for (int i = 0; i < 100000; i++)
            //{
            //    db.HashSet("studenths" + i, "name", "張三" + i);
            //    db.HashSet("studenths" + i, "age", 12 + i);
            //    db.HashSet("studenths" + i, "class", "五年級" + i);
            //}
            //Console.WriteLine(sw.Elapsed.TotalMilliseconds);
            //sw.Restart();
            for (int i = 0; i < 100000; i++)
            {
                db.StringSet("studentstr_name" + i, "張三" + i);
                db.StringSet("studentstr_age" + i, 12 + i);
                db.StringSet("studentstr_class" + i, "五年級" + i);
            }
            Console.WriteLine(sw.Elapsed.TotalMilliseconds);
            //for (int i = 0; i < 100000; i++)
            //{
            //    db.KeyDelete("studenths" + i);
            //    db.KeyDelete("studentstr_name" + i);
            //    db.KeyDelete("studentstr_age" + i);
            //    db.KeyDelete("studentstr_class" + i);
            //}
            Console.ReadLine();
        }

StackExchange.Redis學習筆記(二) Redis查詢 五種數據類型的應用