zoukankan      html  css  js  c++  java
  • ASP.NET 缓存

    (一)什么是缓存

        缓存是指临时数据或者文件交换区。比方说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 }
  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/Johnny_Z/p/2348438.html
Copyright © 2011-2022 走看看