StackExchange.Redis学习笔记(一) Redis的使用初探
Redis
- Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化。
- 与其它键值数据存储相比,Redis有一组相对丰富的数据类型。
- Redis可以将数据复制到任意数量的从机中
Redis的安装
官网只提供了linux的安装包,我win10 的系统,在github上下载的windows安装包 3.0.504最新稳定版的
github地址:https://github.com/MicrosoftArchive/redis/releases
官网下载地址:https://redis.io/download
将压缩包解压到文件夹后,双击“redis-server.exe”即可启动redis服务,也可以在环境变量中配置之后,用redis-server 命令来开启服务,以下是服务启动成功界面
Redis的使用
C#可选用ServiceStack.Redis或者StackExchange.Redis等客户端程序操作redis,由于ServiceStack.Redis已经收费了,我这里用的是StackExchange.Redis,通过Nuget安装到项目中
接下来我们创建一个操作redis的帮助类:
public static class StackExchangeRedisHelper
{
private static readonly string Coonstr = ConfigurationManager.ConnectionStrings["RedisExchangeHosts"].ConnectionString;//
private static object _locker = new Object();
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;
}
} static StackExchangeRedisHelper()
{
} /// <summary>
///
/// </summary>
/// <returns></returns>
public static IDatabase GetDatabase()
{
return Instance.GetDatabase();
} /// <summary>
/// 这里的 MergeKey 用来拼接 Key 的前缀,具体不同的业务模块使用不同的前缀。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string MergeKey(string key)
{
return BaseSystemInfo.SystemCode + key;
}
/// <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 object Get(string key)
{
key = MergeKey(key);
return Deserialize<object>(GetDatabase().StringGet(key));
} /// <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>
/// <param name="key"></param>
/// <returns></returns>
public static bool Exists(string key)
{
key = MergeKey(key);
return GetDatabase().KeyExists(key); //可直接调用
} /// <summary>
/// 移除指定key的缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Remove(string key)
{
key = MergeKey(key);
return GetDatabase().KeyDelete(key);
} /// <summary>
/// 异步设置
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public static async Task SetAsync(string key, object value)
{
key = MergeKey(key);
await GetDatabase().StringSetAsync(key, Serialize(value));
} /// <summary>
/// 根据key获取缓存对象
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static async Task<object> GetAsync(string key)
{
key = MergeKey(key);
object value = await GetDatabase().StringGetAsync(key);
return value;
} /// <summary>
/// 实现递增
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static long Increment(string key)
{
key = MergeKey(key);
//三种命令模式
//Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
//Async,异步模式直接走的是Task模型。
//Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
//即发即弃:通过配置 CommandFlags 来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
return GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
} /// <summary>
/// 实现递减
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static long Decrement(string key, string value)
{
key = MergeKey(key);
return GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);
} /// <summary>
/// 序列化对象
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
static byte[] Serialize(object o)
{
if (o == null)
{
return null;
}
BinaryFormatter binaryFormatter = new BinaryFormatter();
using (MemoryStream memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, o);
byte[] objectDataAsStream = memoryStream.ToArray();
return objectDataAsStream;
}
} /// <summary>
/// 反序列化对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="stream"></param>
/// <returns></returns>
static T Deserialize<T>(byte[] stream)
{
if (stream == null)
{
return default(T);
}
BinaryFormatter binaryFormatter = new BinaryFormatter();
using (MemoryStream memoryStream = new MemoryStream(stream))
{
T result = (T)binaryFormatter.Deserialize(memoryStream);
return result;
}
}
/// <summary>
/// 配置更改时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
{
LogHelper.WriteInfoLog("Configuration changed: " + e.EndPoint);
}
/// <summary>
/// 发生错误时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
{
LogHelper.WriteInfoLog("ErrorMessage: " + e.Message);
}
/// <summary>
/// 重新建立连接之前的错误
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
{
LogHelper.WriteInfoLog("ConnectionRestored: " + e.EndPoint);
}
/// <summary>
/// 连接失败 , 如果重新连接成功你将不会收到这个通知
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
{
LogHelper.WriteInfoLog("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));
}
/// <summary>
/// 更改集群
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
{
LogHelper.WriteInfoLog("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
}
/// <summary>
/// redis类库错误
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
{
LogHelper.WriteInfoLog("InternalError:Message" + e.Exception.Message);
} //场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
//建立连接后,通过调用ConnectionMultiplexer.GetDatabase 方法返回对 Redis Cache 数据库的引用。从 GetDatabase 方法返回的对象是一个轻量级直通对象,不需要进行存储。 /// <summary>
/// 使用的是Lazy,在真正需要连接时创建连接。
/// 延迟加载技术
/// 微软azure中的配置 连接模板
/// </summary>
//private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
//{
// //var options = ConfigurationOptions.Parse(constr);
// ////options.ClientName = GetAppName(); // only known at runtime
// //options.AllowAdmin = true;
// //return ConnectionMultiplexer.Connect(options);
// ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);
// muxer.ConnectionFailed += MuxerConnectionFailed;
// muxer.ConnectionRestored += MuxerConnectionRestored;
// muxer.ErrorMessage += MuxerErrorMessage;
// muxer.ConfigurationChanged += MuxerConfigurationChanged;
// muxer.HashSlotMoved += MuxerHashSlotMoved;
// muxer.InternalError += MuxerInternalError;
// return muxer;
//}); #region 当作消息代理中间件使用 一般使用更专业的消息队列来处理这种业务场景
/// <summary>
/// 当作消息代理中间件使用
/// 消息组建中,重要的概念便是生产者,消费者,消息中间件。
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public static long Publish(string channel, string message)
{
ISubscriber sub = Instance.GetSubscriber();
//return sub.Publish("messages", "hello");
return sub.Publish(channel, message);
} /// <summary>
/// 在消费者端得到该消息并输出
/// </summary>
/// <param name="channelFrom"></param>
/// <returns></returns>
public static void Subscribe(string channelFrom)
{
ISubscriber sub = Instance.GetSubscriber();
sub.Subscribe(channelFrom, (channel, message) =>
{
Console.WriteLine((string)message);
});
}
#endregion /// <summary>
/// GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
/// 有时候需要为单个服务器指定特定的命令
/// 使用IServer可以使用所有的shell命令,比如:
/// DateTime lastSave = server.LastSave();
/// ClientInfo[] clients = server.ClientList();
/// 如果报错在连接字符串后加 ,allowAdmin=true;
/// </summary>
/// <returns></returns>
public static IServer GetServer(string host, int port)
{
IServer server = Instance.GetServer(host, port);
return server;
} /// <summary>
/// 获取全部终结点
/// </summary>
/// <returns></returns>
public static EndPoint[] GetEndPoints()
{
EndPoint[] endpoints = Instance.GetEndPoints();
return endpoints;
} } internal class BaseSystemInfo
{
internal static readonly string SystemCode="000A";
}
测试代码
static void Main(string[] args)
{
RedisTest();
}
public static void RedisTest()
{
Console.WriteLine("Redis写入缓存:Name:张三丰");
StackExchangeRedisHelper.Set("Name", "张三丰", new TimeSpan(, , , , ));
Console.WriteLine("Redis获取缓存:Name:" + StackExchangeRedisHelper.Get("Name").ToString());
Thread.Sleep();
Console.WriteLine("一秒后Redis获取缓存:Name:" + StackExchangeRedisHelper.Get("Name")??"");
Console.ReadKey();
}
也可以通过Execute来直接运行redis命令
Redis加入Windows服务
由于关闭控制台redis就自动关闭了,所以把redis加入windows服务更好一些
切换到redis目录下运行命令:redis-server --service-install redis.windows-service.conf --loglevel verbose
移除服务:--service-uninstal
开启服务:redis-server --service-start
关闭服务:redis-server --service-stop
在开启Redis服务时遇到一些坑,
redis.windows-service.conf中配置:
1. logfile "Logs/redis_log.txt"需要有对应的目录
2.将bind 127.0.0.1注释去掉
3.依然有问题,后参考一篇文章 http://blog.csdn.net/fengzhihen2007/article/details/52211048
直到出现successfully started服务启动成功
StackExchange.Redis学习笔记(一) Redis的使用初探的更多相关文章
- Redis学习笔记(4) Redis事务、生存时间及排序
1. Redis事务 Redis中的事务(transaction)是一组命令的集合,一个事务中的命令要么都执行,要么都不执行.事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次 ...
- Redis学习笔记(1) Redis介绍及基础
1. Redis的特性 (1) 存储结构 Redis(Remote Dictionary Server,远程字典服务器)是以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容.Redis支 ...
- redis学习笔记之redis简介
redis简介 Redis是一个开源的,高性能的,基于键值对的缓存与存储系统,通过设置各种键值数据类型来适应不同场景下的缓存与存储需求.同事redis的诸多高层级功能使其可以胜任消息队列,任务队列等不 ...
- Redis学习笔记之Redis单机,伪集群,Sentinel主从复制的安装和配置
0x00 Redis简介 Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值 ...
- StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用
ConnectionMultiplexer ConnectionMultiplexer 是StackExchange.Redis的核心对象,用这个类的实例来进行Redis的一系列操作,对于一个整个应用 ...
- redis学习笔记(三)——redis的命令大全总结
总结了一些redis五种存储类型的常用命令以及一些通用操作命令,不是很全,是在学习的时候将学到的做了个汇总,使用的时候可以查一下. 笔记写在表格里面了,不好粘贴.......后面的直接截图了..... ...
- Redis学习笔记(3) Redis基础类型及命令之二
1. 集合类型 集合类型与列表类型有很多相似之处,但二者的区别在于:前者具有唯一性,但不具有有序性:后者具有有序性,但不具有唯一性.集合类型的常用操作是向集合中加入或删除元素.判断某个元素是否存在等, ...
- Redis学习笔记(2) Redis基础类型及命令之一
1. 基础命令 (1) 获取符合规则的键名列表 格式为:KEYS pattern 其中pattern表示支持通配符 # 建立一个名为bar的键 > SET bar OK # 获取Redis所有键 ...
- Redis学习笔记之Redis基本数据结构
Redis基础数据结构 Redis有5种基本数据结构:String(字符串).list(列表).set(集合).hash(哈希).zset(有序集合) 字符串string 字符串类型是Redis的va ...
随机推荐
- 【原】zookeeper集群配置常见问题说明
zookeeper集群网上demo一大堆,补充一下一些不明白的地方 1 复制2份zookeeper,savle作为备份节点 2.配置zoo.cfg # The number of millisecon ...
- HDU 2276 Kiki & Little Kiki 2 矩阵构造
Kiki & Little Kiki 2 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java ...
- Tomcat配置连接c3p0连接池
一.Tomcat配置JNDI资源 JNDI(Java Naming and Directory Interface),Java 命名和目录接口. JNDI的作用就是:在服务器上配置资源,然后通过统一的 ...
- csharp: Gets a files formatted size.
/* ASP.NET 默认上传文件是4M ,可以修改服务配置.. <system.web> <!-- 指示 ASP.NET 支持的最大文件上载大小. 该限制可用于防止因用户将大量文件 ...
- BZOJ5465: [APIO 2018] 选圆圈(K-D Tree)
题意 题目链接 Sol 下面是错误做法,正解请看这里 考虑直接用K-D tree模拟.. 刚开始想的是维护矩形最大最小值,以及子树中最大圆的位置,然后... 实际上最大圆的位置是不用维护的,直接把原序 ...
- 1142 奖学金 sort做法
个人博客:doubleq.win 1142 奖学金 2007年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 题目 ...
- 理解webpack4.splitChunks
一.前言 之前一直也没有研究过webpack4是基于怎样的规则去拆分模块的,现在正好有时间打算好好了解一下,看了官方文档也陆陆续续的看了看网上别人写的文章,感觉大部分都是将官方文档翻译了一遍,很多问题 ...
- SQL-OVER与四种排名函数:ROW_NUMBER(),RANK(),DENSE_RANK(),NTILE()
1 SELECT orderid,custid,val, ROW_NUMBER() OVER(ORDER BY val) AS rownum, RANK() OVER(ORDER BY val) AS ...
- mysql中int、bigint、smallint 和 tinyint的区别与长度的含义【转】
最近使用mysql数据库的时候遇到了多种数字的类型,主要有int,bigint,smallint和tinyint.其中比较迷惑的是int和smallint的差别.今天就在网上仔细找了找,找到如下内容, ...
- leetcode Ch8-Others
1. Rotate Image 旋转图像 顺时针旋转90度:先沿水平线翻转,再沿主对角线翻转. 逆时针旋转90度:先沿竖直线翻转,再沿主对角线翻转. 顺时针旋转180度:水平翻转和竖直翻转各一次. 逆 ...