StackExchange.Redis 访问封装类
本文内容纲要:
最近需要在C#中使用Redis,在Redis的官网找到了ServiceStack.Redis,最后在测试的时候发现这是个坑,4.0已上已经收费,后面只好找到3系列的最终版本,最后测试发现还是有BUG或者是我不会用。没有办法,最好找到了StackExchange.Redis,支持异步的客户端,据说性能比ServiceStack.Redis更好,而且据说StackOverflow也是使用的这个客户端,里面有支持4.0和4.5的版本,现将我在使用中的封装类提供出来给大家参考(参考了网上的一些资料):
usingDotNet.Log;
///<summary>
///StackExchangeRedisHelper
///
///在StackExchange.Redis中最重要的对象是ConnectionMultiplexer类,它存在于StackExchange.Redis命名空间中。
///这个类隐藏了Redis服务的操作细节,ConnectionMultiplexer类做了很多东西,在所有调用之间它被设计为共享和重用的。
///不应该为每一个操作都创建一个ConnectionMultiplexer。ConnectionMultiplexer是线程安全的,推荐使用下面的方法。
///在所有后续示例中,都假定你已经实例化好了一个ConnectionMultiplexer类,它将会一直被重用,
///现在我们来创建一个ConnectionMultiplexer实例。它是通过ConnectionMultiplexer.Connect或者ConnectionMultiplexer.ConnectAsync,
///传递一个连接字符串或者一个ConfigurationOptions对象来创建的。
///连接字符串可以是以逗号分割的多个服务的节点.
///
///
///注意:
///ConnectionMultiplexer实现了IDisposable接口当我们不再需要是可以将其释放的,这里我故意不使用using来释放他。
///简单来讲创建一个ConnectionMultiplexer是十分昂贵的,一个好的主意是我们一直重用一个ConnectionMultiplexer对象。
///一个复杂的的场景中可能包含有主从复制,对于这种情况,只需要指定所有地址在连接字符串中(它将会自动识别出主服务器)
///ConnectionMultiplexerredis=ConnectionMultiplexer.Connect("server1:6379,server2:6379");
///假设这里找到了两台主服务器,将会对两台服务进行裁决选出一台作为主服务器来解决这个问题,这种情况是非常罕见的,我们也应该避免这种情况的发生。
///
///
///这里有个和ServiceStack.Redis大的区别是没有默认的连接池管理了。没有连接池自然有其利弊,最大的好处在于等待获取连接的等待时间没有了,
///也不会因为连接池里面的连接由于没有正确释放等原因导致无限等待而处于死锁状态。缺点在于一些低质量的代码可能导致服务器资源耗尽。不过提供连接池等阻塞和等待的手段是和作者的设计理念相违背的。StackExchange.Redis这里使用管道和多路复用的技术来实现减少连接
///
///参考:http://www.cnblogs.com/Leo_wl/p/4968537.html
///
///修改记录
///
///2016.04.07版本:1.0SongBiao主键创建。
///
///<author>
///<name>SongBiao</name>
///<date>2016.04.07</date>
///</author>
///</summary>
publicstaticclassStackExchangeRedisHelper
{
privatestaticreadonlystringCoonstr=ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;
privatestaticobject_locker=newObject();
privatestaticConnectionMultiplexer_instance=null;
///<summary>
///使用一个静态属性来返回已连接的实例,如下列中所示。这样,一旦ConnectionMultiplexer断开连接,便可以初始化新的连接实例。
///</summary>
publicstaticConnectionMultiplexerInstance
{
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;
}
}
staticStackExchangeRedisHelper()
{
}
///<summary>
///
///</summary>
///<returns></returns>
publicstaticIDatabaseGetDatabase()
{
returnInstance.GetDatabase();
}
///<summary>
///这里的MergeKey用来拼接Key的前缀,具体不同的业务模块使用不同的前缀。
///</summary>
///<paramname="key"></param>
///<returns></returns>
privatestaticstringMergeKey(stringkey)
{
returnBaseSystemInfo.SystemCode+key;
}
///<summary>
///根据key获取缓存对象
///</summary>
///<typeparamname="T"></typeparam>
///<paramname="key"></param>
///<returns></returns>
publicstaticTGet<T>(stringkey)
{
key=MergeKey(key);
returnDeserialize<T>(GetDatabase().StringGet(key));
}
///<summary>
///根据key获取缓存对象
///</summary>
///<paramname="key"></param>
///<returns></returns>
publicstaticobjectGet(stringkey)
{
key=MergeKey(key);
returnDeserialize<object>(GetDatabase().StringGet(key));
}
///<summary>
///设置缓存
///</summary>
///<paramname="key"></param>
///<paramname="value"></param>
publicstaticvoidSet(stringkey,objectvalue)
{
key=MergeKey(key);
GetDatabase().StringSet(key,Serialize(value));
}
///<summary>
///判断在缓存中是否存在该key的缓存数据
///</summary>
///<paramname="key"></param>
///<returns></returns>
publicstaticboolExists(stringkey)
{
key=MergeKey(key);
returnGetDatabase().KeyExists(key);//可直接调用
}
///<summary>
///移除指定key的缓存
///</summary>
///<paramname="key"></param>
///<returns></returns>
publicstaticboolRemove(stringkey)
{
key=MergeKey(key);
returnGetDatabase().KeyDelete(key);
}
///<summary>
///异步设置
///</summary>
///<paramname="key"></param>
///<paramname="value"></param>
publicstaticasyncTaskSetAsync(stringkey,objectvalue)
{
key=MergeKey(key);
awaitGetDatabase().StringSetAsync(key,Serialize(value));
}
///<summary>
///根据key获取缓存对象
///</summary>
///<paramname="key"></param>
///<returns></returns>
publicstaticasyncTask<object>GetAsync(stringkey)
{
key=MergeKey(key);
objectvalue=awaitGetDatabase().StringGetAsync(key);
returnvalue;
}
///<summary>
///实现递增
///</summary>
///<paramname="key"></param>
///<returns></returns>
publicstaticlongIncrement(stringkey)
{
key=MergeKey(key);
//三种命令模式
//Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
//Async,异步模式直接走的是Task模型。
//Fire-and-Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
//即发即弃:通过配置CommandFlags来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
returnGetDatabase().StringIncrement(key,flags:CommandFlags.FireAndForget);
}
///<summary>
///实现递减
///</summary>
///<paramname="key"></param>
///<paramname="value"></param>
///<returns></returns>
publicstaticlongDecrement(stringkey,stringvalue)
{
key=MergeKey(key);
returnGetDatabase().HashDecrement(key,value,flags:CommandFlags.FireAndForget);
}
///<summary>
///序列化对象
///</summary>
///<paramname="o"></param>
///<returns></returns>
staticbyte[]Serialize(objecto)
{
if(o==null)
{
returnnull;
}
BinaryFormatterbinaryFormatter=newBinaryFormatter();
using(MemoryStreammemoryStream=newMemoryStream())
{
binaryFormatter.Serialize(memoryStream,o);
byte[]objectDataAsStream=memoryStream.ToArray();
returnobjectDataAsStream;
}
}
///<summary>
///反序列化对象
///</summary>
///<typeparamname="T"></typeparam>
///<paramname="stream"></param>
///<returns></returns>
staticTDeserialize<T>(byte[]stream)
{
if(stream==null)
{
returndefault(T);
}
BinaryFormatterbinaryFormatter=newBinaryFormatter();
using(MemoryStreammemoryStream=newMemoryStream(stream))
{
Tresult=(T)binaryFormatter.Deserialize(memoryStream);
returnresult;
}
}
///<summary>
///配置更改时
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerConfigurationChanged(objectsender,EndPointEventArgse)
{
LogHelper.WriteInfoLog("Configurationchanged:"+e.EndPoint);
}
///<summary>
///发生错误时
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerErrorMessage(objectsender,RedisErrorEventArgse)
{
LogHelper.WriteInfoLog("ErrorMessage:"+e.Message);
}
///<summary>
///重新建立连接之前的错误
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerConnectionRestored(objectsender,ConnectionFailedEventArgse)
{
LogHelper.WriteInfoLog("ConnectionRestored:"+e.EndPoint);
}
///<summary>
///连接失败,如果重新连接成功你将不会收到这个通知
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerConnectionFailed(objectsender,ConnectionFailedEventArgse)
{
LogHelper.WriteInfoLog("重新连接:Endpointfailed:"+e.EndPoint+","+e.FailureType+(e.Exception==null?"":(","+e.Exception.Message)));
}
///<summary>
///更改集群
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerHashSlotMoved(objectsender,HashSlotMovedEventArgse)
{
LogHelper.WriteInfoLog("HashSlotMoved:NewEndPoint"+e.NewEndPoint+",OldEndPoint"+e.OldEndPoint);
}
///<summary>
///redis类库错误
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
privatestaticvoidMuxerInternalError(objectsender,InternalErrorEventArgse)
{
LogHelper.WriteInfoLog("InternalError:Message"+e.Exception.Message);
}
//场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
//建立连接后,通过调用ConnectionMultiplexer.GetDatabase方法返回对RedisCache数据库的引用。从GetDatabase方法返回的对象是一个轻量级直通对象,不需要进行存储。
///<summary>
///使用的是Lazy,在真正需要连接时创建连接。
///延迟加载技术
///微软azure中的配置连接模板
///</summary>
//privatestaticLazy<ConnectionMultiplexer>lazyConnection=newLazy<ConnectionMultiplexer>(()=>
//{
////varoptions=ConfigurationOptions.Parse(constr);
//////options.ClientName=GetAppName();//onlyknownatruntime
////options.AllowAdmin=true;
////returnConnectionMultiplexer.Connect(options);
//ConnectionMultiplexermuxer=ConnectionMultiplexer.Connect(Coonstr);
//muxer.ConnectionFailed+=MuxerConnectionFailed;
//muxer.ConnectionRestored+=MuxerConnectionRestored;
//muxer.ErrorMessage+=MuxerErrorMessage;
//muxer.ConfigurationChanged+=MuxerConfigurationChanged;
//muxer.HashSlotMoved+=MuxerHashSlotMoved;
//muxer.InternalError+=MuxerInternalError;
//returnmuxer;
//});
#region当作消息代理中间件使用一般使用更专业的消息队列来处理这种业务场景
///<summary>
///当作消息代理中间件使用
///消息组建中,重要的概念便是生产者,消费者,消息中间件。
///</summary>
///<paramname="channel"></param>
///<paramname="message"></param>
///<returns></returns>
publicstaticlongPublish(stringchannel,stringmessage)
{
ISubscribersub=Instance.GetSubscriber();
//returnsub.Publish("messages","hello");
returnsub.Publish(channel,message);
}
///<summary>
///在消费者端得到该消息并输出
///</summary>
///<paramname="channelFrom"></param>
///<returns></returns>
publicstaticvoidSubscribe(stringchannelFrom)
{
ISubscribersub=Instance.GetSubscriber();
sub.Subscribe(channelFrom,(channel,message)=>
{
Console.WriteLine((string)message);
});
}
#endregion
///<summary>
///GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
///有时候需要为单个服务器指定特定的命令
///使用IServer可以使用所有的shell命令,比如:
///DateTimelastSave=server.LastSave();
///ClientInfo[]clients=server.ClientList();
///如果报错在连接字符串后加,allowAdmin=true;
///</summary>
///<returns></returns>
publicstaticIServerGetServer(stringhost,intport)
{
IServerserver=Instance.GetServer(host,port);
returnserver;
}
///<summary>
///获取全部终结点
///</summary>
///<returns></returns>
publicstaticEndPoint[]GetEndPoints()
{
EndPoint[]endpoints=Instance.GetEndPoints();
returnendpoints;
}
}
}
本文内容总结:
原文链接:https://www.cnblogs.com/hnsongbiao/p/5414728.html