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