C#版-Redis緩存服務器在Windows下的使用


Redis緩存服務器是一款key/value數據庫,讀110000次/s,寫81000次/s,因為是內存操作所以速度飛快,常見用法是存用戶token、短信驗證碼等

官網顯示Redis本身並沒有Windows版本的,微軟官方開發了基於Windows的Redis服務器:MSOpenTech/redis

 

一、Redis服務端

 

首先下載Redis服務器,點擊前往下載.msi版本,雙擊安裝Redis服務端就有了,並以服務的形式隨系統一起啟動:

 

 

安裝好Redis服務器之后第一件事就是設置密碼,進入安裝目錄:C:\Program Files\Redis - 找到配置文件:redis.windows-service.conf - 找到:# requirepass foobared - 回車換行加上:requirepass 這里寫自己的新密碼(頂行寫,前面不要留空格) - 到服務里重啟Redis服務,或者重啟電腦

不設置密碼的壞處,看看攜程這哥們的遭遇就知道了:記一次Redis被攻擊的事件

 

二、Redis客戶端(命令行和可視化工具RDM)

 

命令行方式演示:啟動Redis客戶端、讀寫Redis服務器

 

 

上圖命令解釋:

 

cd C:\Program Files\Redis:cd命令進入Redis安裝目錄,相當於Windows系統里雙擊進入Redis的安裝目錄

 

redis-cli.exe:打開redis-cli客戶端程序,相當於Windows系統里雙擊運行一個exe程序(安裝了上面的Redis服務端程序,需要一個客戶端程序連接這個服務端。連接本機redis服務器直接敲此命令,連接遠程的需要加ip和端口,例:redis-cli.exe -h 111.11.11.111 -p 6379)

 

keys *:查看所有鍵值對(如果Redis服務器設置了密碼,這條命令會報錯,需要先輸入密碼,執行此命令:auth 你的密碼)

 

set blog oppoic.cnblogs.com:設置一個鍵值對,鍵是:blog,值是:oppoic.cnblogs.com(按目錄存儲:set 目錄名:鍵 值)

 

get blog:獲取鍵為blog對應的值

 

keys *:查看所有鍵值對

 

其他常用命令:

 

config get dir:獲取redis安裝目錄

 

ping:返回PONG表示redis服務器正常

 

redis-cli.exe:進入第一個數據庫(默認),redis一共0到15共16個庫,進入第三個庫 redis-cli -n 2(已經進去了,select 0~15 隨意切換)

 

quit:退出redis程序

 

exit:退出dos窗口

 

flushdb:刪除當前選擇數據庫中的所有key

 

flushall:刪除所有數據庫中的數據庫

 

更多命令:https://redis.io/commands

 

至此,一個運行在本機的Redis緩存服務器已經搭建完成,並且可以讀寫了。但是命令行顯然對小白用戶不友好,可視化工具登場:Redis Desktop Manager(https://redisdesktop.com/download)

 

左側樹顯示已經有一個連接了,點擊底部的Connect to Redis Server再添加一個連接:

 

Name:連接名稱,隨便起

 

Host:主機地址,本機就是127.0.0.1,遠程的輸入對應IP

 

Port:端口,Redis服務器默認端口6379

 

Auth:密碼,設置了就輸,沒設置留空

 

連上Redis服務器就可以看到,默認16個庫(配置文件可改),索引從0開始。常見用法是一個項目一個庫,項目下不同功能模塊分不同目錄存在這個庫下。

 

有了可視化工具之后的操作就不用說了,雙擊,右鍵新建、刪除。。。會用Windows系統的都會用這個工具。相比於命令行,Redis Desktop Manager這個可視化工具更友好,調試遠程服務器上的數據也更方便,指哪打哪。

 

注:本機可以這樣,連接遠程服務器需要到服務器上的Redis安裝目錄下,找到redis.windows-service.conf文件,找到bind 127.0.0.1 前面加"#"注釋掉,然后到服務里右鍵重啟redis服務,或者重啟Windows系統

 

三、C#操作Redis服務器

 

以上都是命令行和可視化工具操作Redis服務器,C#程序操作Redis需要借助StackExchange.Redis(https://github.com/StackExchange/StackExchange.Redis),為了統一調用,封裝了一個RedisHelper幫助類:

 

using Newtonsoft.Json;

using StackExchange.Redis;

using System;

using System.ComponentModel;

using System.Configuration;

using System.Reflection;

using System.Text;

 

namespace redis_Demo

{

    /// <summary>

    /// Redis 幫助類

    /// </summary>

    public static class RedisHelper

    {

        private static string _conn = ConfigurationManager.AppSettings["redis_connection_string"] ?? "127.0.0.1:6379";

        private static string _pwd = ConfigurationManager.AppSettings["redis_connection_pwd"] ?? "123456";

 

        static ConnectionMultiplexer _redis;

        static readonly object _locker = new object();

 

        #region 單例模式

        public static ConnectionMultiplexer Manager

        {

            get

            {

                if (_redis == null)

                {

                    lock (_locker)

                    {

                        if (_redis != null) return _redis;

 

                        _redis = GetManager();

                        return _redis;

                    }

                }

                return _redis;

            }

        }

 

        private static ConnectionMultiplexer GetManager(string connectionString = null)

        {

            if (string.IsNullOrEmpty(connectionString))

            {

                connectionString = _conn;

            }

            var options = ConfigurationOptions.Parse(connectionString);

            options.Password = _pwd;

            return ConnectionMultiplexer.Connect(options);

        }

        #endregion

 

        /// <summary>

        /// 添加

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="value"></param>

        /// <param name="expireMinutes">過期時間,單位:分鍾。默認600分鍾</param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        /// <returns></returns>

        public static bool StringSet(CacheFolderEnum folder, string key, string value, int expireMinutes = 600, int db = -1)

        {

            string fd = GetDescription(folder);

            return Manager.GetDatabase(db).StringSet(string.IsNullOrEmpty(fd) ? key : fd + ":" + key, value, TimeSpan.FromMinutes(expireMinutes));

        }

 

        /// <summary>

        /// 獲取

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        /// <returns></returns>

        public static string StringGet(CacheFolderEnum folder, string key, int db = -1)

        {

            try

            {

                string fd = GetDescription(folder);

                return Manager.GetDatabase(db).StringGet(string.IsNullOrEmpty(fd) ? key : fd + ":" + key);

            }

            catch (Exception)

            {

                return null;

            }

        }

 

        /// <summary>

        /// 刪除

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        /// <returns></returns>

        public static bool StringRemove(CacheFolderEnum folder, string key, int db = -1)

        {

            try

            {

                string fd = GetDescription(folder);

                return Manager.GetDatabase(db).KeyDelete(string.IsNullOrEmpty(fd) ? key : fd + ":" + key);

            }

            catch (Exception)

            {

                return false;

            }

        }

        /// <summary>

        /// 是否存在

        /// </summary>

        /// <param name="key"></param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        public static bool KeyExists(CacheFolderEnum folder, string key, int db = -1)

        {

            try

            {

                string fd = GetDescription(folder);

                return Manager.GetDatabase(db).KeyExists(string.IsNullOrEmpty(fd) ? key : fd + ":" + key);

            }

            catch (Exception)

            {

                return false;

            }

        }

 

        /// <summary>

        /// 延期

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="min">延長時間,單位:分鍾,默認600分鍾</param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        public static bool AddExpire(CacheFolderEnum folder, string key, int min = 600, int db = -1)

        {

            try

            {

                string fd = GetDescription(folder);

                return Manager.GetDatabase(db).KeyExpire(string.IsNullOrEmpty(fd) ? key : fd + ":" + key, DateTime.Now.AddMinutes(min));

            }

            catch (Exception)

            {

                return false;

            }

        }

 

        /// <summary>

        /// 添加實體

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="t">實體</param>

        /// <param name="ts">延長時間,單位:分鍾,默認600分鍾</param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        public static bool Set<T>(CacheFolderEnum folder, string key, T t, int expireMinutes = 600, int db = -1)

        {

            string fd = GetDescription(folder);

            var str = JsonConvert.SerializeObject(t);

            return Manager.GetDatabase(db).StringSet(string.IsNullOrEmpty(fd) ? key : fd + ":" + key, str, TimeSpan.FromMinutes(expireMinutes));

        }

 

        /// <summary>

        /// 獲取實體

        /// </summary>

        /// <param name="folder">目錄</param>

        /// <param name="key"></param>

        /// <param name="db">庫,默認第一個。0~15共16個庫</param>

        public static T Get<T>(CacheFolderEnum folder, string key, int db = -1) where T : class

        {

            string fd = GetDescription(folder);

            var strValue = Manager.GetDatabase(db).StringGet(string.IsNullOrEmpty(fd) ? key : fd + ":" + key);

            return string.IsNullOrEmpty(strValue) ? null : JsonConvert.DeserializeObject<T>(strValue);

        }

 

        /// <summary>

        /// 獲得枚舉的Description

        /// </summary>

        /// <param name="value">枚舉值</param>

        /// <param name="nameInstead">當枚舉值沒有定義DescriptionAttribute,是否使用枚舉名代替,默認是使用</param>

        /// <returns>枚舉的Description</returns>

        private static string GetDescription(this Enum value, Boolean nameInstead = true)

        {

            Type type = value.GetType();

            string name = Enum.GetName(type, value);

            if (name == null)

            {

                return null;

            }

 

            FieldInfo field = type.GetField(name);

            DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;

 

            if (attribute == null && nameInstead == true)

            {

                return name;

            }

            return attribute == null ? null : attribute.Description;

        }

    }

}

 

向redis服務器第一個庫的fd1目錄里,添加一個鍵為name,值為wangjie的記錄:

 

RedisHelper.StringSet(CacheFolderEnum.Folder1, "name", "wangjie");

 

獲取這條記錄:

 

string key = RedisHelper.StringGet(CacheFolderEnum.Folder1, "name");

Console.WriteLine("鍵為name的記錄對應的值:" + key);

 

刪除這條記錄:

 

bool result = RedisHelper.StringRemove(CacheFolderEnum.Folder1, "name");

if (result)

{

    Console.WriteLine("鍵為name的記錄刪除成功");

}

else

{

    Console.WriteLine("鍵為name的記錄刪除失敗");

}

查詢這條記錄是否存在:

bool ifExist = RedisHelper.KeyExists(CacheFolderEnum.Folder1, "name");

if (ifExist)

{

    Console.WriteLine("鍵為name的記錄存在");

}

else

{

    Console.WriteLine("鍵為name的記錄不存在");

}

向redis服務器第二個庫的fd2目錄里,添加一個鍵為sd1,值為一個對象的記錄:

 

Student student = new Student() { Id = 1, Name = "張三", Class = "三年二班" };

RedisHelper.Set<Student>(CacheFolderEnum.Folder2, "sd1", student, 10, 1);

 

獲取這個對象:

Student sdGet = RedisHelper.Get<Student>(CacheFolderEnum.Folder2, "sd1", 1);

if (sdGet != null)

{

    Console.WriteLine("Id:" + sdGet.Id + " Name:" + sdGet.Name + " Class:" + sdGet.Class);

}

else

{

    Console.WriteLine("找不到鍵為sd1的記錄");

}

源碼:(http://files.cnblogs.com/files/oppoic/redis_Demo.zip)

 

環境是VS 2013,如果跑不起來自行把cs里的代碼拷出來編譯運行

 

四、其他

 

MSOpenTech開發Redis緩存服務器自帶持久化,寫入之后重啟電腦鍵值對還存在,一般寫入鍵值對要設置過期時間,否則一直占用內存不會被釋放。Redis存儲方式不光有鍵對應字符串,還有對應List,HashTable等,當然Redis更多高階的用法還是在Linux下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM