C# redis 的簡單應用

region 準備參數

        var connStr = "localhost:6379,password=";

        var db = 2;

        SiteRedisHelper redisHelper = new SiteRedisHelper(connStr, "monster", db);

        var key = "MessageQueue";

        var msg = string.Empty;

        #endregion

消息寫入+讀取(入門版)

        #region 添加消息

        while (true)
        {

            Console.WriteLine("請輸入你需要發送的消息");
            msg = Console.ReadLine();

            if (!string.IsNullOrWhiteSpace(msg))
            {
                //                    var listLeftPush = redisHelper.ListLeftPush(key, msg);//添加一條消息並返回已添加消息數量
                var listLeftPushAsync = redisHelper.ListLeftPushAsync(key, msg);//異步添加

                //追加事件
                listLeftPushAsync.ContinueWith((task =>
                {
                    if (task.IsCompletedSuccessfully)
                    {
                        Console.WriteLine($"消息添加完畢,此消息隊列共有{task.Result}條信息");
                    }
                }));

            }
            else
            {
                Console.WriteLine("停止發送消息");
                break;
            }

        };

        #endregion

        #region 讀取消息

        while (!string.IsNullOrWhiteSpace(msg = redisHelper.ListLeftPop(key)))
        {
            Console.WriteLine("消息出列:" + msg);
            Debug.WriteLine("消息出列:" + msg);
            FileLogTools.Write(msg, "RedisMSMQ.Try");
        }

        #endregion

運行結果

相對來說還是挺簡單的,也沒有遇上什麼奇怪的異常,此處便不做什麼太多說明

將實體做爲消息進行寫入/讀取

稍微改造了一下使用對象做爲消息進行寫入/讀取

<實體類>
public class MsgEntity
{

    public string Content { get; set; }

    public DateTimeOffset CreateTime { get; set; }

}

<添加相關>
    var msgCount = redisHelper.ListLeftPush<MsgEntity>(key,new MsgEntity()
    {
        Content = msg,
        CreateTime = DateTimeOffset.Now
    });

    Console.WriteLine($"添加成功,消息站已有{msgCount}條消息");

<讀取的消息>
    1.原始:
           ����          DRedisMSMQ.Try, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   RedisMSMQ.Try.Entity.MsgEntity   <Content>k__BackingField<CreateTime>k__BackingFieldSystem.DateTimeOffset      hello����System.DateTimeOffset   DateTime
OffsetMinutes  
'NCN���

    ... 一串亂碼 + 一堆命名空間 看來寫入需要調整

    2.調整 : 
        <old>
    private static byte[] Serialize(object obj)
    {
        try
        {
            if (obj == null)
                return null;
            var binaryFormatter = new BinaryFormatter();
            using (var memoryStream = new MemoryStream())
            {
                binaryFormatter.Serialize(memoryStream, obj);
                var data = memoryStream.ToArray();
                return data;
            }
        }
        catch (SerializationException ex)
        {
            throw ex;
        }
    }
    
        <new>
    JsonConvert.SerializeObject(redisValue)

2.1 讀取同樣處理

<異常記錄>
    1.添加時異常:System.Runtime.Serialization.SerializationException:“Type 'RedisMSMQ.Try.Entity.MsgEntity' in Assembly 'RedisMSMQ.Try, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.”

    說明:此對象在程序集中不可進行序列化
    處理:給類添加特性[Serializable]

使用實體時,處理也是非常簡單的,主要是注意一下轉string的方式,
個人使用的是JsonConvert 進行序列化/反序列化(json比較簡潔,工具類功能也比較齊全) 其次就是編碼一致

模擬簡單的發佈/訂閱

        #region 準備參數

        var connStr = "localhost:6379,password=";

        var db = 2;

        SiteRedisHelper redisHelper = new SiteRedisHelper(connStr, "monster", db);

        var key = "entrepot";

        var model = default(Produce);

        #endregion

        #region 審覈線程,訂閱申請消息,給予相應的處理

        ThreadPool.QueueUserWorkItem((state =>
        {
            Thread.Sleep(1000);
            while (IsDealValid)
            {
                var validMsg = redisHelper.ListRightPop<Produce>(key);
                if (validMsg != null && !validMsg.IsNull())
                {
                    Console.WriteLine($"正在審覈產品:{JsonConvert.SerializeObject(validMsg)}");
                }
            }
        }));

        #endregion

        #region 主線程_添加產品

        Console.WriteLine("歡迎來到產品中心,請填寫產品註冊資料");

        IsDealValid = true;

        while ((model = Produce.RegisterProduce())!= null)
        {
            var validCount = redisHelper.ListLeftPush<Produce>(key, model);//將註冊資料添加到消息隊列中
            Console.WriteLine($"產品註冊申請正在處理中……,在您之前共有{validCount-1}個產品正在處理,請耐心等待審覈結果");
        }

        #endregion

發佈/訂閱

        #region 訂閱消息

        ThreadPool.QueueUserWorkItem((state =>
        {
            redisHelper.Subscribe(channel, ((redisChannel, value) =>
            {
                //Console.WriteLine($"訂閱方收到一條消息:{JsonConvert.SerializeObject(value)}");

                if (!value.IsNullOrEmpty)
                {
                    Console.WriteLine($"訂閱方收到一條消息:{value.ToString()}");
                }

            }));

            Console.WriteLine("子線程已訂閱消息");

        }));

        #endregion

        #region 主線程發佈消息

        while ((model = Produce.RegisterProduce()) != null)
        {
            var receiveCount = redisHelper.Publish(channel, model);
            Console.WriteLine($"此條消息已被{receiveCount}個人訂閱");
        }

        #endregion

發佈訂閱 vs 消息隊列

1. 消息隊列中的消息不能重複讀取,發佈訂閱中的消息由訂閱方共享
2. 若發佈時沒有訂閱方,後續加入的訂閱方將不能收到此條消息。在消息隊列中,若消息沒有及時出列,消息將會繼續保存在消息隊列中

總結

總體來說,redis的操作都是比較簡單的,因爲官方已經有集成api供我們調用,所以操作起來還是沒什麼難度,只需要瞭解方法的應用就可以了,複雜一點的,應該就是業務流程的一些具體應用,應用場景的使用,效率的提升

相關類說明:

SiteRedisHelper

參考博文:http://www.cnblogs.com/liqingwen/archive/2017/04/06/6672452.html

    《構造方法》

    public SiteRedisHelper(string connStr, string defaultKey, int db = -1)
    {
        //連接字符串
        ConnectionString = connStr;
        //建立連接
        _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
        //默認前綴【無實用】
        DefaultKey = defaultKey;
        //註冊相關事件  【未應用】
        RegisterEvent();
        //獲取Database操作對象
        _db = _connMultiplexer.GetDatabase(db);
    }

author:monster

since:7/9/2018 11:25:14 AM

direction:redis mssq analysis

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章