标签:memcached
这件事要从早之前说起,先前,我们考试系统中说要一起讲一下底层的东西。当时,组长给我和一清分的这个Memcached这个东西,要我们整理一下,然后给大家讲一讲。起初的东西不知道如何下手,因为没有资料、没有视频等等,我就找了九期的师哥要了一些资料,通过这些资料,我们做出了一些Demo,当时我们做出来之后,就没有真正运用到项目中,后来ITOO项目3.0开始后,底层说要叫几个负责模块的人,因为当时我做过这个方面,我就担任了底层缓存的任务。
我们底层之前是这样写的,在底层类库中:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</configSections>
<enyim.com>
<memcached>
<servers>
<add address="127.0.0.1" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
<memcached keyTransformer="Enyim.Caching.TigerHashTransformer, Enyim.Caching">
<servers>
<add address="127.0.0.1" port="11211" />
</servers>
<socketPool minPoolSize="2" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</configuration></span>写入我们自己封装的Memecached类:
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Enyim.Caching;
using Enyim.Caching.Memcached;
using Enyim.Caching.Configuration;
namespace ITOO.Library.Core.Memcache
{
public static class MemcacheHelper
{
private static MemcachedClient mc;
static MemcacheHelper()
{
mc=new MemcachedClient();
}
/// <summary>
/// 当缓存中没有数据的时候将数据写入缓存
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool Add(string key, object value)
{
return mc.Store(StoreMode.Add, key, value);
}
/// <summary>
/// 当缓存中没有数据的时候将数据写入缓存(含过期时间)
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresAt">过期时间</param>
/// <returns></returns>
public static bool Add(string key, object value, DateTime expiresAt)
{
return mc.Store(StoreMode.Add, key, value,expiresAt);
}
/// <summary>
/// 替换缓存中的数据
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool Replace(string key, object value)
{
return mc.Store(StoreMode.Replace, key, value);
}
/// <summary>
/// 替换缓存中的数据(含过期时间)
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresAt">过期时间</param>
/// <returns></returns>
public static bool Replace(string key, object value, DateTime expiresAt)
{
return mc.Store(StoreMode.Replace, key, value, expiresAt);
}
/// <summary>
/// 尝试获取缓存
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryGet(string key, out object value)
{
return mc.TryGet(key, out value);
}
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static T Get<T>(string key)
{
return mc.Get<T>(key);
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static object Get(string key)
{
return mc.Get(key);
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Remove(string key)
{
return mc.Remove(key);
}
/// <summary>
/// 获取一组缓存
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
public static IDictionary<string, object> Get(IEnumerable<string> keys)
{
return mc.Get(keys);
}
}
}</span>
<span style="font-size:18px;">using Enyim.Caching; using Enyim.Caching.Memcached; using Enyim.Caching.Configuration;</span>
初步的时候,调用MemcacheHelper方法中的:
<span style="font-size:18px;"> /// <summary>
/// 当缓存中没有数据的时候将数据写入缓存(含过期时间)
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresAt">过期时间</param>
/// <returns></returns>
public static bool Add(string key, object value, DateTime expiresAt)
{
return mc.Store(StoreMode.Add, key, value,expiresAt);
}</span>
方法的时候,根据说明第二个参数就是Object类型的,应该是可以的,但是报了一个错:
未标记为可序列化
但是就查了查,意思很简单就是:序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。简单一点说,就是在我们自己定义的对象上添加添加为:Serializable。
我们在定义实体的时候,就要这样写:
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ITOO.Library.Test
{
[Serializable]
public class MM
{
public string s1;
public string s2;
public string s4;
}
}</span>
<span style="font-size:18px;"> //以下代码片段说明了如何将此类的一个实例序列化为一个文件:
MM obj = new MM();
obj.s1 = "1";
obj.s2 = "24";
obj.s4 = "一些字符串";
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Create,
FileAccess.Write, FileShare.None);
formatter.Serialize(stream, obj);
stream.Close();</span>
下面的代码是将一个文件反序列化为对象:
<span style="font-size:18px;"> //将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。以下代码片段说明了如何进行此操作。
IFormatter formatter1 = new BinaryFormatter();
Stream stream1 = new FileStream("MyFile.bin", FileMode.Open,
FileAccess.Read, FileShare.Read);
MyObject obj1 = (MyObject)formatter1.Deserialize(stream1);
stream1.Close();
Console.WriteLine("n1: {0}", obj1.n1);
Console.WriteLine("n2: {0}", obj1.n2);
Console.WriteLine("str: {0}", obj1.str);</span>其实我们用的就是IO流的技术将一个对象的数据,存数为一个文件流,在讲文件流反序列化为对象,就可以了。
当然这就给我们一个思路就是我们可以将对象通过流的技术,将对象序列化为string类型,然后存储在缓存中,当从缓存中取出的时候,我们就可以将这个string类型的反序列化为对象类型就可以了。
这样就出现了一个问题,我们不能将缓存存为文件类型保存到本地,这样数据就会暴漏。因此,就将IO流的思想封装在了序列化和反序列化两个方法中:
<span style="font-size:18px;"> #region Serialize<T>(T obj)--邱慕夏--2015年4月21日15:52:43
/// <summary>
/// 序列化 对象到字符串
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static string Serialize<T>(T obj)
{
try
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, obj);
stream.Position = 0;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Flush();
stream.Close();
return Convert.ToBase64String(buffer);
}
catch (Exception ex)
{
throw new Exception("序列化失败,原因:" + ex.Message);
}
}
#endregion
#region Desrialize<T>(T obj, string str)--邱慕夏--2015年4月21日15:53:11
/// <summary>
/// 反序列化 字符串到对象
/// </summary>
/// <param name="obj">泛型对象</param>
/// <param name="str">要转换为对象的字符串</param>
/// <returns>反序列化出来的对象</returns>
public static T Desrialize<T>(T obj, string str)
{
try
{
obj = default(T);
IFormatter formatter = new BinaryFormatter();
byte[] buffer = Convert.FromBase64String(str);
MemoryStream stream = new MemoryStream(buffer);
obj = (T)formatter.Deserialize(stream);
stream.Flush();
stream.Close();
}
catch (Exception ex)
{
throw new Exception("反序列化失败,原因:" + ex.Message);
}
return obj;
}
#endregion
</span>
然后根据这两个方法,封装缓存中object和string类型之间转化:
<span style="font-size:18px;"> #region Set(string key, object value, DateTime expiry)---邱慕夏--2015年4月21日14:14:52
public static bool Set(string key, object value, DateTime expiry)
{
string m1;
m1 = Serialize(value);
return mc.Set(key, m1, expiry);
}
#endregion
#region T GetObject<T>(T obj, string key)--邱慕夏--2015年4月21日15:52:23
/// <summary>
/// 获取Memcache
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static T GetObject<T>(T obj, string key)
{
string m1 = (string)mc.Get(key);
obj = (T)Desrialize(obj, m1);
return obj;
}
#endregion</span>这样,我们就可以调用方法了:
<span style="font-size:18px;"> MemcacheHelper.Add("syq1", "我是底层", DateTime.Now.AddMinutes(20));
MM mm = new MM();
mm.s1 = "123";
mm.s2 = "1234567";
mm.s4 = "123480-5";
MemcacheHelper.Set("k12", mm, DateTime.Now.AddMinutes(20));
MM m2 = new MM();
MM m1 = (MM)MemcacheHelper.GetObject(m2, "k12");</span>
同时,我们不想每次都要调用MemcacheHelper之前,都要配置一次缓存文件,怎么办?
于是我们就将缓存文件中的配置都去掉,只用了AppSetting节点,来实现对memecache的配置:
配置文件如下:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</configSections>
<appSettings>
<!--注意这里的Serverlist添加的时候,要是添加的数组,将用“,”分开-->
<add key="serverlist" value="127.0.0.1:11211" />
</appSettings>
<!--<enyim.com>
<memcached>
<servers>
<add address="127.0.0.1" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
<memcached keyTransformer="Enyim.Caching.TigerHashTransformer, Enyim.Caching">
<servers>
<add address="127.0.0.1" port="11211" />
</servers>
<socketPool minPoolSize="2" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>-->
</configuration>
</span>
完整的MemcacheHelper封装:
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using Memcached.ClientLibrary;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace ITOO.Library.Core.Memcache
{
public class MemcacheHelper
{
private static MemcachedClient mc;
#region MemcacheByCsharp--邱慕夏--2015年4月21日15:54:00
/// <summary>
/// 连接Memcache
/// </summary>
static MemcacheHelper()
{
//String[] serverlist = { "127.0.0.1:11211" };
string server = ConfigurationManager.AppSettings["serverlist"];
string[] serverlist;
serverlist = server.Split(',');
// initialize the pool for memcache servers
SockIOPool pool = SockIOPool.GetInstance("test");
pool.SetServers(serverlist);
pool.Initialize();
mc = new MemcachedClient();
mc.PoolName = "test";
mc.EnableCompression = false;
}
#endregion
#region Set(string key, object value, DateTime expiry)---邱慕夏--2015年4月21日14:14:31
/// <summary>
/// 设置Memcache的值
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiry"></param>
/// <returns></returns>
//public static bool Set(string key, object value, DateTime expiry)
//{
// IFormatter formatter = new BinaryFormatter();
// Stream stream = new FileStream(key, FileMode.Create,
// FileAccess.Write, FileShare.None);
// formatter.Serialize(stream, value);
// stream.Close();
// bool flag;
// flag = true;
// return flag;
// //return mc.Set(key, stream, expiry);
//}
#endregion
#region Set(string key, object value, DateTime expiry)---邱慕夏--2015年4月21日14:14:52
public static bool Set(string key, object value, DateTime expiry)
{
string m1;
m1 = Serialize(value);
return mc.Set(key, m1, expiry);
}
#endregion
#region T GetObject<T>(T obj, string key)--邱慕夏--2015年4月21日15:52:23
/// <summary>
/// 获取Memcache
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static T GetObject<T>(T obj, string key)
{
string m1 = (string)mc.Get(key);
obj = (T)Desrialize(obj, m1);
return obj;
}
#endregion
#region Serialize<T>(T obj)--邱慕夏--2015年4月21日15:52:43
/// <summary>
/// 序列化 对象到字符串
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static string Serialize<T>(T obj)
{
try
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, obj);
stream.Position = 0;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Flush();
stream.Close();
return Convert.ToBase64String(buffer);
}
catch (Exception ex)
{
throw new Exception("序列化失败,原因:" + ex.Message);
}
}
#endregion
#region Desrialize<T>(T obj, string str)--邱慕夏--2015年4月21日15:53:11
/// <summary>
/// 反序列化 字符串到对象
/// </summary>
/// <param name="obj">泛型对象</param>
/// <param name="str">要转换为对象的字符串</param>
/// <returns>反序列化出来的对象</returns>
public static T Desrialize<T>(T obj, string str)
{
try
{
obj = default(T);
IFormatter formatter = new BinaryFormatter();
byte[] buffer = Convert.FromBase64String(str);
MemoryStream stream = new MemoryStream(buffer);
obj = (T)formatter.Deserialize(stream);
stream.Flush();
stream.Close();
}
catch (Exception ex)
{
throw new Exception("反序列化失败,原因:" + ex.Message);
}
return obj;
}
#endregion
/// <summary>
/// 当缓存中没有数据的时候将数据写入缓存
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool Add(string key, object value)
{
return mc.Set(key, value);
}
/// <summary>
/// 当缓存中没有数据的时候将数据写入缓存(含过期时间)
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresAt">过期时间</param>
/// <returns></returns>
public static bool Add(string key, object value, DateTime expiresAt)
{
return mc.Set(key, value, expiresAt);
}
/// <summary>
/// 替换缓存中的数据
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool Replace(string key, object value)
{
return mc.Replace(key, value);
}
/// <summary>
/// 替换缓存中的数据(含过期时间)
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresAt">过期时间</param>
/// <returns></returns>
public static bool Replace(string key, object value, DateTime expiresAt)
{
return mc.Replace(key, value, expiresAt);
}
/// <summary>
/// 尝试获取缓存,判断是否存在
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
//public static bool TryGet(string key, out object value)
//{
// return mc.KeyExists(key);
//}
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static object Get(string key)
{
return mc.Get(key);
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Remove(string key)
{
return mc.Delete(key);
}
/// <summary>
/// 获取一组缓存
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
public static IDictionary<string, object> Get(IEnumerable<string> keys)
{
List<string> list = new List<string>();
List<object> tempobj = new List<object>();
IDictionary<string, object> obj = new Dictionary<string, object>();
foreach (String slabId in keys)
{
list.Add(slabId);
}
for(int i=0;i<list.Count();i++){
tempobj.Add(mc.Get(list[i]));
obj.Add(list[i], tempobj);
}
return obj;
}
}
}</span>
<span style="font-size:18px;">using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using ITOO.Library.Core.Memcache;
using Memcached.ClientLibrary;
namespace ITOO.Library.Test
{
public class test
{
public static void Main(string[] arg)
{
#region 使用底层的MemcacheHelper
////使用底层的MemcacheHelper
MemcacheHelper.Add("syq1", "我是底层", DateTime.Now.AddMinutes(20));
MM mm = new MM();
mm.s1 = "123";
mm.s2 = "1234567";
mm.s4 = "123480-5";
MemcacheHelper.Set("k12", mm, DateTime.Now.AddMinutes(20));
MM m2 = new MM();
MM m1 = (MM)MemcacheHelper.GetObject(m2, "k12");
string[] m= new string[]{"syq1"};
IDictionary<string, object> obj = new Dictionary<string, object>();
obj = MemcacheHelper.Get(m);
#endregion
}
}
}</span>
<span style="font-size:18px;"><appSettings> <!--注意这里的Serverlist添加的时候,要是添加的数组,将用“,”分开--> <add key="serverlist" value="127.0.0.1:11211" /> </appSettings></span>
这件事情,因为当时,我们一起研究了Memcache所以,有机会封装底层的MemcacheHelper的方法,真正在项目中使用,上手也很快,大概用了几个小时就解决了这个问题,当然解决这个问题的时候,遇到了很多的问题,将问题一个一个的解决的过程就是我们不断学习的过程,就像老师说的那样:让我们拥有了“我一定能解决这个问题”的决心。我们在项目中也是想到了如何让用户更加便捷的使用,简化了配置文件,这一点上,也做了努力。
所以我觉得,做一个东西,我们需要的是一份自信、一份为用户服务的心。
标签:memcached
原文地址:http://blog.csdn.net/qiumuxia0921/article/details/45225923