缓存二、HttpRuntime.Cache用法
上一篇写了Asp.net页面缓存,本篇介绍在服务器端进行缓存。微软.net给我提供了HttpRuntime.Cache对象进行缓存。个人对缓存的理解是,将从数据库、文件、或业务逻辑计算出来的数据,保存在内存中,当下一次遇到相同内容的请求就直接将保存在内存中的数据返回给请求者。这样做的好处是可以提高访问效率,减少文件或是数据库的读取,属于"以空间换时间",适当的运用好Cache可以很大程度提高程序性能。关于Cache本文所包含的内容有
-
Page.Cache,HttpRuntime.Cache,HttpContext.Current.Cache的区别
-
Cache用法
-
Cache项依赖关系
一、Page.Cache,HttpRuntime.Cache,HttpContext.Current.Cache的区别
在代码中可以通过以Page.Cache,HttpRuntime.Cache,HttpContext.Current.Cache三种方式引用到Cache对象,那这三种方式有什么区别呢,在网上查询了相关文档后,通过Reflect实践查看,找出具体代码。为便于理解,先看以下Reflect中截图:
(1)HttpContext.Current.Cache
(2)Page.Cache
(3)HttpRuntime.Cache
通过Reflect代码查看器,可以确定的是HttpContext. Current.Cache指向的是HttpRuntime.Cache。而Page.Cache指向的是一个内部变量internal Cache _cache;为什么说这里是指向HttpContext.Current.Cache?本人猜测是因为this指向的是HttpContext.Current,不知是否正确,希望园友指点,谢谢!
需要注意的是在Asp.net中HttpRuntime.Cache为静态对象,方便我们调用,一般直接用HttpRunTime.Cache就可以。
二、Cache用法
从元数据中查看Cache主要有Add/Get/Insert/Remove等方法,Add方法只有一个,Insert方法却有多个重载这是为什么呢?我们还是通过Reflect查看代码实现,来了解它们之间的区别。先查看Add方法的代码,从下图中可以看到,Add调用的是return this._cacheInternal.DoInsert方法
再来看Insert方法,居然也是调用this._cacheInternal.DoInsert方法,两者的唯一区别是,Add函数是有返回而Insert的是无返回的。
对于Add函数返回值,微软是这样解释的:如果该项先前存储在 Cache 中,则为 System.Object,否则为 null。也就是第一次的添加key至缓存时,返回为null,而以后再执行Add方法添加同一key时返回的是第一次Add的值。 结合之前我在博客园里看到的文章,指出Add方法添加缓存时,如果Key已存在是不修改原来的值,没有做任何修改,查询Cache.Count也没有增加。那我们用Add函数编程时是要根据返回null或Object来判断当前Key是否已存在吗?我们来写测试代码,通过Add方法重复添加两个Key值,再查看返回值的变化。
我们通过代码来测试:
static void Main(string[] args)
{
string str1 = "I'm str1";
//第一次通过Add方法加入Key[str1]
//返回值:null
object obj1 = HttpRuntime.Cache.Add("str1", str1, null, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.Default, null);
//value1=I'm str1
string value = HttpRuntime.Cache.Get("str1").ToString();
//第二次通过Add方法加入Key[str1]
//返回值:I'm str1
object obj2 = HttpRuntime.Cache.Add("str1", "hello i'm str2!", null, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.Default, null);
//value2=I'm str1
string value2 = HttpRuntime.Cache.Get("str1").ToString();
//通过Insert方法添加Key[str1]
HttpRuntime.Cache.Insert("str1", "hello i'm str3 by insert!");
//value3=hello i'm str3 by insert!
string value3 = HttpRuntime.Cache.Get("str1").ToString();
}
上面的代码,我把Key=str1的对象执行了两次Add函数一次Insert函数,执行结果表明,当第一次调用Add时,是向Cache里写入一个值,并且返回的是null。第二次调用Add时返回的是第一次写入的值。第三次调用Insert时把第一次写入的值给覆盖了,至此Add和Insert的区别已经清楚了,结果请查看以下截图:
三、缓存项依赖关系
CacheDependency
缓存项依赖关系,是很有用的一个功能,它是与自定议的缓存对象的一大区别(如静态对象),不需要自已写逻辑去维护缓存的失效。比如有两个缓存项key1、key2,当key1值变化时,key2自动失效,我们通过以下代码来实现这个功能:
static void Main(string[] args)
{
//创建两个缓存,并且key2依赖于key1,当key1发生改变时,key2失效
HttpRuntime.Cache.Insert("key1", "key1-1");
CacheDependency dep = new CacheDependency(null, new string[] { "key1" });
HttpRuntime.Cache.Insert("key2", "key2-1", dep,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);
Console.WriteLine("key1=" + HttpRuntime.Cache.Get("key1"));
Console.WriteLine("key2=" + HttpRuntime.Cache.Get("key2"));
Console.WriteLine("\n修改key1值:");
HttpRuntime.Cache.Insert("key1", "key1-2");
Console.WriteLine("key1=" + HttpRuntime.Cache.Get("key1"));
Console.WriteLine("key2=" + HttpRuntime.Cache.Get("key2"));
//Console.WriteLine("\n修改key2值:");
//HttpRuntime.Cache.Insert("key2", "key2-2");
//Console.WriteLine("key1=" + HttpRuntime.Cache.Get("key1"));
//Console.WriteLine("key2=" + HttpRuntime.Cache.Get("key2"));
Console.ReadLine();
}
上面说的是缓存项的依赖,也可以设置缓存对于文件的依赖。在实际应用中,用于根据文件内容计算了一个MD5值当文件内容改变时,让缓存失效重新计算MD5。也可用于缓存XML、webConfig文件,当值改变时让缓存失效。下面给出样例代码,把txt作为缓存对象,当内容变更时,实现缓存失效重新读取文件内容。
static void Main(string[] args)
{
//文件路径
string path = System.Environment.CurrentDirectory;
int i = path.IndexOf("bin");
path = Path.Combine(path.Substring(0, i), "time.txt");
//读取文件内容
string content = "";
using (StreamReader sr = new StreamReader(File.OpenRead(path)))
{
content = sr.ReadToEnd();
}
CacheDependency dep = new CacheDependency(path);
//1.写入缓存
HttpRuntime.Cache.Insert("key1", DateTime.Now, dep);
//2.读取缓存
Console.WriteLine("缓存项key1=" + HttpRuntime.Cache.Get("key1"));
//3.修改文件
Console.WriteLine("\n在文件中添加内容!\n");
using (StreamWriter sw = File.AppendText(path))
{
sw.Write("\n" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.ffff") + "\n");
}
//4.读取缓存
Thread td = new Thread(delegate()
{
Thread.Sleep(1000);
Console.WriteLine("缓存项key1=" + HttpRuntime.Cache.Get("key1"));
});
td.Start();
Console.ReadLine();
}
在文件内容被修改后,可以看到再次读取key1时值为空了(如下图)。在第三步向文件中添加内容后,再次读取缓存时缓存已失效了。这样就达到了让缓存项依赖于文件目的。
CacheDependency也可以同时指定依赖文件、依赖缓存项、还可以依赖于另一个缓存依赖项。用法很多,在实际应用中根据不同情况指定依赖对象,需要我们自己去发现及体会,如果用的恰当,可以为我们省下许多判断代码,并提升程序性能。
//检查依赖多个文件,也依赖多个缓存键值
CacheDependency mydep = new CacheDependency(new string[] { "data.xml", "data1.xml" }, new string[] { "Category", "Category1" });
//关联依赖,还可以依赖于另一个文件缓存依赖
CacheDependency mydep2 = new CacheDependency(new string[] { "data.xml", "data1.xml" }, new string[] { "Category", "Category1" }, mydep);