(一)什么是缓存
缓存是指临时数据或者文件交换区。比方说CPU上的L1或是L2缓存,内存上被划分出来的缓冲区。我们知道CPU的速度是最快的,其次是内存,最后是硬盘,各个部件之间运算速度有很大的差距,但是各个部件之间又需要交互,由于部件之间运算速度差距大,若是CPU频繁的去访问内存,或者内存频繁的访问硬盘,势必很消耗性能并且效率也很低。若是他们能访问跟自己运算速度差不多的区域,如有必要再由该区域去访问比自己速度更慢的区域(如内存或是硬盘),则能带来更高的性能提升。
(二)为什么Web应用程序需要缓存
这主要是为了减轻Web服务器压力,在客户端提供了缓存机制,当用户访问的网页内容无变化的请求时就会调用缓存中的内容,这样一来减轻了服务器压力,避免无必要的重复操作,使用户网页浏览速度加快,用户体验更好。
(三)缓存依赖
被缓存的文件或者页面发生变化时,cache将会失效。
下面具体介绍各种缓存应用。
(四)WebConfig中配置Cache
在webconfig中caching节点下可以设置整个应用程序是否启用缓存,它优先于页面上的缓存配置,是对整个Web应用程序的整体设置。
配置代码 1 <system.web>2 <caching>3 <outputCache enableOutputCache="false"/>4 </caching>5 </system.web>
(五)页面中的Cache
在页面的顶部设置如下代码:
<%@ OutputCache Duration="5" VaryByParam="none" %>
即可对整个页面进行缓存,下面对其中的参数做个简单的说明。
Duration,以秒为单位的缓存时间。
VaryByParam,缓存的内容根据请求参数的不同,缓存多个版本,若有多个参数用分号(;)分割。
VarByControl,根据用户控件中服务器控件ID缓存多个版本。
VaryByHeader,根据请求的HTTP头,缓存不同的版本。
下面来看两个例子。
例5.1
页面前台代码:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PageCache.aspx.cs" Inherits="PageCache" %> 2 <%@ OutputCache Duration="5" VaryByParam="none" %> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 4 <html xmlns="http://www.w3.org/1999/xhtml"> 5 <head runat="server"> 6 <title></title> 7 </head> 8 <body> 9 <form id="form1" runat="server">10 <div>11 <p>本页面时间:<%=DateTime.Now.ToString() %></p>12 </div>13 </form>14 </body>15 </html>后台不书写任何的代码,我们可以看到该页面被缓存了5秒。
例5.2
页面前台代码:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CacheProfiles.aspx.cs" Inherits="CacheProfiles" %> 2 <%@ OutputCache CacheProfile="CacheProfiles" VaryByParam="none"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 4 <html xmlns="http://www.w3.org/1999/xhtml"> 5 <head runat="server"> 6 <title></title> 7 </head> 8 <body> 9 <form id="form1" runat="server">10 <div>11 <%= DateTime.Now.ToString() %>12 </div>13 </form>14 </body>15 </html>在WebConfig文件中配置CacheProfiles,如下:
配置代码 1 <system.web>2 <caching>3 <outputCacheSettings>4 <outputCacheProfiles>5 <add name="CacheProfiles" duration="10"/>6 </outputCacheProfiles>7 </outputCacheSettings>8 </caching>9 </system.web>后台不书写任何代码,我们看到这次页面被缓存了10秒,采用这种方式可以单独对某个页面进行缓存的配置,也可以对一些页面进行统一配置,如果要修改只需修改配置文件即可。
(六)页面局部Cache
页面局部缓存分为两种,一种是对页面较少的部分进行缓存,我们可以用用户控件来实现;另一种是对页面的大部分缓存,只有少部分需要动态改变,我们可以用缓存后替换。下面分别介绍这两种方式。
6.1用户控件缓存
我们先来创建一个简单的用户控件ascx文件,前台代码如下:
用户控件前台代码 1 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %>2 <%@ OutputCache Duration="10" VaryByParam="none" %>3 <span>4 用户控件时间:<%=DateTime.Now.ToString() %>5 </span>没有后台代码,其中设置了过期时间为10秒。我们再来创建一个页面,前台代码如下:
页面前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PartCache.aspx.cs" Inherits="PartCache" %> 2 <%@ Register Src="~/WebUserControl.ascx" tagname="UserControl" TagPrefix="MyControl" %> 3 <%@ OutputCache Duration="20" VaryByParam="none" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head runat="server"> 7 <title></title> 8 </head> 9 <body>10 <form id="form1" runat="server">11 <p>本页面时间:<%=DateTime.Now.ToString() %></p>12 <div>13 <MyControl:UserControl ID="c" runat="server" />14 </div>15 </form>16 </body>17 </html>没有后台代码,页面中缓存过期时间设置为20秒,把用户控件拖拽到该页面中。这里面有个规则,如果页面的缓存时间大于控件的缓存时间,则按照页面的缓存时间为主,与用户控件的缓存时间无关;如果页面的缓存时间小于用户控件的缓存时间,则各走个的缓存时间。
6.2缓存后替换
有两个控件支持该功能一个是Substitution控件,另一个是AdRotator控件,这里只介绍前者。前台代码如下:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="PartCacheV2.aspx.cs" Inherits="PartCacheV2" %> 2 <%@ OutputCache Duration="10" VaryByParam="none" %> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 4 <html xmlns="http://www.w3.org/1999/xhtml"> 5 <head runat="server"> 6 <title></title> 7 </head> 8 <body> 9 <form id="form1" runat="server">10 <div>11 <asp:Substitution ID="Substitution1" runat="server" MethodName="GetTime" />12 </div>13 </form>14 </body>15 </html>代码中设置了页面的缓存时间为10秒。后台代码:
后台代码 1 public static string GetTime(HttpContext context)2 {3 return DateTime.Now.ToString();4 }通过刷新页面我们可以看到Substitution控件中的时间一直在变化,不受页面的缓存控制。
(七)基于文件的Cache
下面的两个例子都是把文件缓存了起来,第一个是缓存单个文件,后面一个是缓存多个文件,它们分别使用了不同的方式达到了同一个效果,当被缓存的文件变化或者缓存到期时,Cache将会失效。
例7.1
首先,在网站的根目录下创建一个TextFile.txt的文本文件,随意在文件中添加些内容。然后创建页面,添加前台代码:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CacheFile.aspx.cs" Inherits="_Default" %> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head runat="server"> 5 <title></title> 6 </head> 7 <body> 8 <form id="form1" runat="server"> 9 <div>10 <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>11 </div>12 </form>13 </body>14 </html>添加后台代码:
后台代码 1 using System.Web.Caching; 2 protected void Page_Load(object sender, EventArgs e) 3 { 4 string info = HttpRuntime.Cache["Info"] as string; 5 if (info == null) 6 { 7 //得到网站目录下的文本文件路径 8 string path = Server.MapPath("~/TextFile.txt"); 9 info = System.IO.File.ReadAllText(path) + DateTime.Now.ToString();10 //把文本文件的内容加上时间加到缓存中11 HttpRuntime.Cache.Add("Info", info, new System.Web.Caching.CacheDependency(path),12 System.Web.Caching.Cache.NoAbsoluteExpiration,13 new TimeSpan(0, 0, 5), //过期策略设置为5秒14 System.Web.Caching.CacheItemPriority.Normal,15 null);//缓存失效时的回调函数16 /*这里也可以使用Insert方法, 如果使用 Insert 方法向缓存添加项,并且已经存在与现有项同名的项,则缓存中的现有项将被替换。17 而Add 方法将返回添加到缓存中的对象。另外,如果使用 Add 方法,并且缓存中已经存在与现有项同名的项,则该方法不会替换该项,并且不会引发异常。18 HttpRuntime.Cache.Insert("Info",info,new System.Web.Caching.CacheDependency(path),19 System.Web.Caching.Cache.NoAbsoluteExpiration,20 new TimeSpan(0,0,5),21 System.Web.Caching.CacheItemPriority.Normal,22 Callback);23 */24 }25 //把信息输出到label标签中26 Label1.Text = info;27 }28 29 private static void Callback(string key, object value, System.Web.Caching.CacheItemRemovedReason reason)30 {31 //缓存过期时的通知函数,缓存失效时添加相关操作32 }例7.2
我们再在网站的根目录下创建一个XMLFile.xml的xml文件,随意在文件中添加些内容。然后创建页面,前台代码:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CacheFileV2.aspx.cs" Inherits="CacheFile" %> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head runat="server"> 5 <title></title> 6 </head> 7 <body> 8 <form id="form1" runat="server"> 9 <div>10 <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>11 </div>12 </form>13 </body>14 </html>后台代码:
后台代码 1 protected void Page_Load(object sender, EventArgs e) 2 { 3 string[] fileDependencies; 4 string fileDependency1 = Server.MapPath("TextFile.txt"); 5 string fileDependency2 = Server.MapPath("XMLFile.xml"); 6 fileDependencies = new String[] { fileDependency1, 7 fileDependency2 }; 8 Response.AddFileDependencies(fileDependencies); 9 //Response.AddFileDependency("");//如果是单个文件,可使用该函数 10 11 Response.Cache.SetExpires(DateTime.Now.AddSeconds(5));12 Response.Cache.SetCacheability(HttpCacheability.Public);13 Response.Cache.SetValidUntilExpires(true);14 15 //测试用,文件改变或者缓存到期,再次请求时,时间就会变化16 Label1.Text = DateTime.Now.ToString();17 }这个例子关联了两个文件,其中任何一个改变都会引起缓存的失效。
以上这两个例子都实现了文件的缓存,但是有一个显著的不同。对于第一个例子,在缓存到期之前如果刷新了页面则缓存时间累加,也就是说页面不会更改,必须在缓存时间内没有刷新页面,过了缓存时间,缓存才会失效。对于第二个例子,不管在缓存时间内如何刷新页面,只要缓存到期,那么页面就会失效。
(八)基于sql的Cache
基于sql的缓存分为两种,一种叫做轮询,一种叫做数据库通知。
轮询:数据库不能通知的时候,应用程序可以主动定期访问数据库,检查数据库是否发生变化。数据库通知:数据库中的数据发生变化时,主动通知应用程序(该功能只支持sql2005以及以上版本)。这里只介绍前一种。首先我们新建一个数据库名为Student,并且创建一张STName的表,该表中有两个字段ID和Name,ID为自增行。
然后,在WebConfig中配置相关设置。
先配置缓存相关设置,其中pollTime为轮询间隔单位为毫秒,即多长时间访问一次数据库。
轮询配置 1 <system.web>2 <caching>3 <sqlCacheDependency enabled="true" pollTime="5000">4 <databases>5 <add connectionStringName="StudentConnectionString" name="Student"/>6 </databases>7 </sqlCacheDependency>8 </caching>9 </system.web>再添加连接字符串。
连接字符串配置 1 <connectionStrings>2 <add name="StudentConnectionString" connectionString="Data Source=.;Initial Catalog=Student;integrated security=true;" providerName="System.Data.SqlClient"/>3 </connectionStrings>前台代码:
前台代码 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="SqlCache.aspx.cs" Inherits="SqlCache" %> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml"> 4 <head runat="server"> 5 <title></title> 6 </head> 7 <body> 8 <form id="form1" runat="server"> 9 <div>10 <asp:GridView ID="GridView1" runat="server">11 </asp:GridView>12 <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>13 </div>14 <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />15 </form>16 </body>17 </html>后台代码:
后台代码 1 using System.Data; 2 using System.Data.SqlClient; 3 using System.Configuration; 4 using System.Web.Caching; 5 6 protected void Page_Load(object sender, EventArgs e) 7 { 8 //判断缓存中是否存在STName 9 if (HttpRuntime.Cache["STName"] == null)10 {11 this.GridView1.DataSource = BindData();12 this.GridView1.DataBind();13 14 //启用更改通知15 SqlCacheDependencyAdmin.EnableNotifications(ConfigurationManager.ConnectionStrings["StudentConnectionString"].ConnectionString);16 //连接到 SQL Server 数据库并为 SqlCacheDependency 更改通知准备数据库表17 SqlCacheDependencyAdmin.EnableTableForNotifications(ConfigurationManager.ConnectionStrings["StudentConnectionString"].ConnectionString, "STName");18 //声明SqlCacheDependency其中构造函数中的这两个参数(Student必需与WebConfig配置的sqlCacheDependency的一致,STName则是缓存的key)19 System.Web.Caching.SqlCacheDependency dep = new System.Web.Caching.SqlCacheDependency("Student", "STName");20 //向缓存集合中插入数据21 HttpRuntime.Cache.Insert("STName", DateTime.Now.ToString(),22 dep,23 System.Web.Caching.Cache.NoAbsoluteExpiration,24 System.Web.Caching.Cache.NoSlidingExpiration,25 System.Web.Caching.CacheItemPriority.Default,26 null);27 //显示缓存STName中的数据28 string str = HttpRuntime.Cache["STName"] as string;29 if (str != null)30 {31 this.Label1.Text = str;32 }33 }34 else//存在则把缓存数据显示到页面35 {36 this.GridView1.DataSource = BindData();37 this.GridView1.DataBind();38 string str = HttpRuntime.Cache["STName"] as string;39 if (str != null)40 {41 this.Label1.Text = str;42 }43 }44 }45 46 protected void Button1_Click(object sender, EventArgs e)47 {48 //更新数据库表中的数据49 UpdateData();50 string str = HttpRuntime.Cache["STName"] as string;51 if (str != null)52 {53 this.Label1.Text = str;54 }55 this.GridView1.DataSource = BindData();56 this.GridView1.DataBind();57 }58 59 60 private SqlConnection returnConnection()61 {62 string connstring = System.Configuration.ConfigurationManager.ConnectionStrings["StudentConnectionString"].ConnectionString;63 SqlConnection conn = new SqlConnection(connstring);64 return conn;65 }66 67 private DataSet BindData()68 {69 /* 读出表中的数据*/70 SqlCommand cmd = new SqlCommand("SELECT * FROM STName", returnConnection());71 SqlDataAdapter sda = new SqlDataAdapter(cmd);72 DataSet ds = new DataSet();73 sda.Fill(ds);74 return ds;75 }76 77 private void UpdateData()78 {79 //更新数据80 SqlConnection con = returnConnection();81 SqlCommand cmd = new SqlCommand("Update STName set Name='cc'", con);82 con.Open();83 cmd.ExecuteNonQuery();84 con.Close();85 }运行后界面:
点击按钮时,更新了Name字段中的值,一个轮询周期内,可以看到时间变了一次。
对于这个例子还有些话要说。当程序执行完上面代码中的SqlCacheDependencyAdmin.EnableTableForNotifications(ConfigurationManager.ConnectionStrings["StudentConnectionString"].ConnectionString, "STName");之后,我们就在数据库中新创建了一张表,如下图:
该表包括了设置表的要监控的字段,还有表是否发生变化的标识,就相当于一个触发器。
另外,代码中对于HttpRuntime.Cache["STName"]的处理,这里没有直接使用像HttpRuntime.Cache["STName"].ToString()代码,对于缓存来说,有可能有外界的原因导致它失效,如果说失效了那HttpRuntime.Cache["STName"]就为空,再访问它的ToString方法就会引发异常。
除了可以对单表进行缓存,也可以对多张表进行缓存,这就会用到AggregateCacheDependency对象,实现方法并不复杂,这里就不再说明。
(九)清除页面缓存
附带一个清除页面缓存的代码,如下:
后台代码 1 protected void Page_Load(object sender, EventArgs e)2 {3 Response.Buffer = true;4 Response.ExpiresAbsolute = DateTime.Now.AddSeconds(-1);5 Response.Expires = 0;6 Response.CacheControl = "no-cache";7 Response.AddHeader("Pragma", "No-Cache");8 }posted on 2012-02-12 22:42 Johnny_Z 阅读( ...) 评论( ...) 编辑 收藏
转载于:https://www.cnblogs.com/Johnny_Z/archive/2012/02/12/2348438.html
