说到Cache我想大家想到最多的还是它对程序性能的改善,我们在谈到网站的优化的时候也会很自然的想到Cache。那么到底什么是Cache呢?Cache又有什么用途呢?
首先请大家想像一下这样的情景,如果我们需要在某个网站的首页展示大量的信息,这些信息每隔一定的时间会进行更新,但是更新的频率不会很高,每个用户对页面进行访问的时候,就需要将大量的数据从后台加载呈现,如果有大量的用户频繁的访问页面的时候,就不得不不断的从后台数据库加载数据并呈现,但是因为信息更新的频率不是很高,所以差不多每次返回的信息几乎都是一样的,这样是不是增加了服务器很多不必要的开销,如果有一种机制,在用户第一次访问的时候对信息进行加载,然后并临时保存,等到再有人访问该页面的时候直接将临时保存的数据展示给用户,而不是去请求服务器,这样是不是很方便?程序的性能肯定可以大幅度的提升。而我们所说的Cache就是这样的一种机制,之所以说它可以很大程度上提高程序的性能,是因为它可以对某些信息进行缓存,以减少服务器不必要的开销。
说了这么多,我想大家已经对Cache有了基本的了解。下面我会通过以下几个方面向大家详细的讲述Cache,并通过相关的示例,向大家展示如何合理的使用Cache。
一、传统的Cache
说到传统的Cache我想大家肯定会想到Request.QueryString(),Session,Application,Cookie等。我也就直接进入正题了,没错就是这些,下面我通过示例向大家展示如何使用这些传统的缓存。
1.1、Request.QueryString()
说到QueryString(),主要用于页面的Url的传值,主要是通过Get方式提交页面表单。演示如下:
1.1.1新建一个Default.aspx页,页面布局如下:
<asp:TextBox ID="txttest" runat="server"></asp:TextBox>
<asp:Button ID="btnset" runat="server" Text="QueryString"
οnclick="btnset_Click" />
1.1.2、cs页处理如下:
string name = txttest.Text;
Response.Redirect("~/Show.aspx?Name="+name);
1.1.3然后再新建一个Show.aspx页,用来显示传递过来的name值,页面只有一个label
1.1.4在Page_load中做如下处理:
if (Request.QueryString["Name"] != null)
{
lbshow.Text = Request["Name"].ToString();
}
1.1.5页面展示为传过来的name值
1.2、Session
Session是唯一标识浏览器或客户端设备请求,并将这些请求映射到服务器上的单独会话实例,可以在服务器上存储特定于会话的数据,Session相对于整个应用程序来说是一个单独的全局的变量。我们通常用Session来标记用户是否登录、临时存储用户的登录名、登录账号等信息,在很多网站的后台管理系统中,多用Session来标记用户是否登录,如果没有登录则直接不能访问后台页。与此同时如果在相应的时间内用户没有和服务器进行交换响应Session就会过期失效,关于Session的一些设置问题不是本节讨论的重点,我会在下一节Asp.net的状态管理机制中做进一步的阐释。好了,下面还是通过示例向大家演示如何使用Session。
1.2.1、页面布局如下:
asp:TextBox ID="txttest" runat="server"></asp:TextBox>
<asp:Button ID="btnSession" runat="server" Text="Session"
οnclick="btnSession_Click" />
1.2.2.在cs页处理如下:
string name = txttest.Text;
Session["name"] = name;
Response.Redirect("~/Show.aspx");
1.2.3新建一个Show.aspx页,只有一个label用来显示Session中的name
在Page_Load中处理如下:
if (Session["name"] != null)
{
lbshow.Text = Session["name"].ToString();
}
1.3 Application
Application是应用程序的一个全局共享的全局变量,也可以用来存储临时的信息,但是用的最多的还是用Application来统计网站的访问数据。作为全局共享变量自然要考虑并发的问题,尤其是在做网站访问统计的时候,如果同时有多个人对网站进行访问,为了准确的统计访问人数,我们需要对Application进行加锁处理,带对访问数据进行处理后再进行解锁,这样在很大程度上可以减少并发,好了,下面向大家演示一下如何通过Application进行网站访问统计。
1.3.1、首先添加一个Global.asax然后在Application_Stat事件中做如下处理:
protected void Application_Start(object sender, EventArgs e)
{
Application.Lock();
{
if (Application["count"] == null)//程序启动时将统计人数设置为0
{
Application["count"] = 0;
}
}
Application.UnLock();
}
1.3.2、然后在Seesion_Start事件中做如下处理,如果有新的用户访问网站,则将访问人数加1
protected void Session_Start(object sender, EventArgs e)
{
Application.Lock();
{
if (Application["count"] != null)
{
Application["count"] = (int)Application["count"] + 1;
}
}
Application.UnLock();
}
1.3.3、如果我们需要在前台页面显示,则直接Application["count"]即可取到网站访问人数。在这里在多少两句,我们这里做的是网站的访问统计,如果要做在线统计的话也很简单,这时需要我们在Seesion_End处理事件中,将在线的人数减一即可,有兴趣的同学可以自己研究下。
1.4 Cookie
在Javascript里边也有Cookie,这里主要讲的是Asp.net里边的Cookie,好了,真奔主题。
通过以下示例向大家演示如何使用Asp.net下的Cookie。
1.4.1、新建页布局如下:
<table>
<tr><td><asp:Label ID="Label1" runat="server" Text="设置Cookie值:"></asp:Label></td>
<td><asp:TextBox ID="txtcookie" runat="server"></asp:TextBox></td></tr>
<tr><td><asp:Label ID="Label2" runat="server" Text="读取Cookie值:"></asp:Label></td> <td><asp:TextBox ID="txtxs" runat="server"></asp:TextBox></td></tr>
<tr><td><asp:Button ID="btnsz" runat="server" Text="设置" οnclick="btnsz_Click" /></td>
<td><asp:Button ID="btnxs" runat="server" Text="显示" οnclick="btnxs_Click"
style="height: 21px" /></td></tr>
</table>
1.4.2、在cs页处理如下:
//设置Cookie
protected void btnsz_Click(object sender, EventArgs e)
{
//Response.Cookies["Name"]=txtcookie.Text;是设置Cookie的另一种方法
HttpCookie cookie = new HttpCookie("Name");
cookie.Value = txtcookie.Text;
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
Response.Write("<script>alert('设置成功!')</script>");
}
//读取Cookie
protected void btnxs_Click(object sender, EventArgs e)
{
if (Request.Cookies["Name"].Value!= null)
{
txtxs.Text = Request.Cookies["Name"].Value.ToString();
}
else
{
Response.Write("<script>alert('读取的Cookie不存在!')</script>");
}
}
这里只是简单的演示了下Cookie的设置和读取,如果我们不设置Cookie的过期时间的话,则它属于非持久性Cookie,会很快的失效,如过我们设置过期时间,则Cookie可以存存在本地文件中、或者Sql Server服务器中,也可以存储在其他服务程序中。
二、页面输出缓存
所谓的页面输出缓存的机制是将Asp.net页的内容缓存入服务器内存,当页面第一次被请求的时候,会对页面进行缓存,当再次请求时,直接从缓存中将页面回发给用户,这样直到缓存过期,然后会再次对页面进行缓存。页面缓存多用于需要大量处理才能编译完成的页,且页面内容不经常变化的页,就像我在文章开头举得那个例子一样。
这里只是举个简单的小例子向大家演示如何进行页面输出缓存。
2.1、新建一个aspx页,上面只放置一个label和一个button按钮,布局如下:
<asp:Label ID="lbshowTime" runat="server" Text=""></asp:Label>
<br />
页面的真实时间:<asp:Substitution ID="Substitution1" runat="server" MethodName="GetCurrentTime" />
<asp:Button ID="btnST" runat="server" Text="ShowTime" οnclick="btnST_Click" />
2.2、然后我们在aspx页做如下处理:
在<%@page%>节点下引入
<%@ OutputCache Duration="30" VaryByParam="none" %>
这句代码的意思是将当前页设置缓存,缓存时间为30秒
2.3、然后我们在.cs页Button的Cilick事件中做如下处理:
protected void btnST_Click(object sender, EventArgs e)
{
lbshowTime.Text = DateTime.Now.ToString();
}
2.4、运行之后我们发现,无论我们如何点击为label进行赋值,label的值都没有任何变化,过了一分钟之后我们再点击设置按钮,会发现时间变了,这是因为我们的Cache时间过期了,然后就会对新的时间进行缓存。细心的朋友可能发现我们在上边引入的高亮还有一个参数是VaryByparam,这个参数有什么作用呢?该参数是指页面根据使用 POST或 GET发送的名称/值对(参数)来更新缓存的内容,多个参数用分号隔开,形如:http://localhost:5435/Show.aspx?Id=4&name=Olive,我们可以设置<%@ OutputCache Duration="30" VaryByParam="p;name" %>。如果不希望根据任何参数来改变缓存内容,请将值设置为 none。如果希望通过所有的参数值改变都更新缓存,请将属性设置为星号 (*).在这里希望大家注意,我们是为每一个参数分别设置缓存的,而不是所有的参数公用一个缓存。事实上<%@OutputCache %>总共支持五个属性(Duration,VaryByParam,Location,VaryByCustom,VaryByHeader),有两个(Duration,VaryByParam)是必须的,这两个在上边已经介绍过了,其他的三个属性VaryByHeader 基于指定的标头中的变动改变缓存条目。VaryByCustom 允许在global.asax中指定自定义变动(例如,“Browser”)。 VaryByHeader和VaryByCustom主要用于根据访问页面的客户端对页面的外观或内容进行自定义。同一个URL可能需要同时为浏览器和移动电话客户端呈现输出,因此,需要针对不同的客户端缓存不同的内容版本。或者,页面有可能已经针对IE进行了优化,针对Netscape或Opera则应取消这种优化功能。三、页面局部缓存。
在上一点我们讲到了页面输出缓存,也就是将整个页面缓存如内存中,但是在实际的开发中用时候并不是需要将页面所有的内存进行缓存,这个时候我们可以用到页面局部缓存。页面局部缓存可以由两部分组成:用户控件缓存和局部缓存。
3.1、用户控件缓存
关于用户控件缓存,我们只需要新建一个用户控件页,然后在其aspx加入<%@OutputCache%>进行相关的缓存设置即可,需要注意的是除了Location属性,对于OutputCache在Web窗体上支持的所有属性,用户控件也同样支持。用户控件还支持名为VaryByControl的OutputCache属性,该属性将根据用户控件的成员的值改变该控件的缓存。如果指定了VaryByControl,可以省略VaryByParam。在默认情况下,对每个页面上的每个用户控件都单独进行缓存。不过,如果一个用户控件不随应用程序中的页面改变,并且在所有页面都使用相同的名称,则可以设置参数Shared的值为“true”,该参数将使用户控件的缓存版本供引用该控件的所有页面使用。3.2、局部缓存
所谓的页面局部缓存,我们可以把它理解为页面替换缓存,在实际的开发中,有时候我们需要将页面的大部分内容进行缓存,但是有少部分的内容则不需要缓存,这个时候就可以用到局部缓存。主要用到了Substitution 控件。下面通过一个示例向大家演示如何进行页面的局部缓存。
3.2.1、新建一个aspx页,页面布局如下:
<asp:Label ID="lbshowTime" runat="server" Text=""></asp:Label>
<br />
页面的真实时间:<asp:Substitution ID="Substitution1" runat="server" MethodName="GetCurrentTime" />
<asp:Button ID="btnST" runat="server" Text="ShowTime" οnclick="btnST_Click" />
3.2.2、然后在aspx页头加入:<%@ OutputCache Duration="30" VaryByParam="none" %>
即对页面进行缓存
3.2.3、在cs页做如下处理:
protected void btnST_Click(object sender, EventArgs e)
{
lbshowTime.Text = DateTime.Now.ToString();
}
protected static string GetCurrentTime(HttpContext hc)
{
return DateTime.Now.ToString();
}
这里我们需要特别的注意一下,我们在前台的页面Substitution控件的一个属性:MethodName的值即为我们后台的函数GetCurrentTime。该属性用于获取或者设置当Substitution控件执行时为回调而调用的方法名称。该方法必须符合以下3条标准:1、此方法必须被定义为静态方法;2、此方法必须接受HttpContext类型的参数;3、此方法必须返回String类型的值。在运行情况下,Substitution控件将自动调用MethodName属性所定义的方法。该方法返回的字符串即为要在页面中的Substitution控件的位置上显示的内容。如果页面设置了缓存全部输出,那么在第一次请求时,该页将运行并缓存其输出。对于后续的请求,将通过缓存来完成,该页上的其他代码不会再运行。但Substitution控件及其有关方法则在每次请求时都执行,并且自动更新该控件所表示的动态内容,这样就实现了整体缓存,局部变化的效果。
四、应用程序缓存(System.Web.Caching.Cache)页面级和用户控件级缓存的确是一种可以迅速而简便地提高站点性能的方法,但是在ASP.NET中除了页面级和用户控件级的缓存之外还有一种更加灵活的方式即Asp.net中提供的Cache类,该类在(System.Web.Caching.Cache)中,我们可以利用Cache对象存储任何可序列化的数据对象,基于一个或多个依赖项的组合来控制缓存条目到期的方式。这些依赖项可以包括自从项被缓存后经过的时间、自从项上次被访问后经过的时间、对文件和/或文件夹的更改以及对其他缓存项的更改,在略作处理后还可以包括对数据库中特定表的更改。这里我就不做具体的示例了,我已经把这里东西封装为一个Cache1类,导出为类模板(点击下载CacheClass.zip),有兴趣的同学可以下载使用以下,里边有Cache的各种使用方法,包括利用缓存依赖来达到缓存的目的等
五、分布式缓存
我们上边所说的那些缓存方法都是基于单服务器的缓存,在实际想开发中如果我们建立分布式的缓存系统的时候,这些就不能满足需求了。因为现阶段对分布式缓存用的比较少,所以对这一块的了解不是很多,所以也不能乱说,在网上看了下有关分布式缓存的东西,很多朋友都推荐使用Memcached创建分布式缓存。这里只是对Memecahed做一个简单的介绍,有兴趣的朋友下去自己了解吧。memcached 是以LiveJournal 旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件,是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。它主要是通过在内存中开辟一块区域来维护一个hash表以加快页面的访问速度,和数据库是相对独立的。任何web服务器都能更新或删除缓存项,并且其他所有其他的服务器都能在下次访问时检测到这些更新。