• 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

    页面前台代码:

    前台代码

     后台不书写任何的代码,我们可以看到该页面被缓存了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,如下:

    配置代码

     后台不书写任何代码,我们看到这次页面被缓存了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控件,这里只介绍前者。前台代码如下:

    前台代码

    代码中设置了页面的缓存时间为10秒。后台代码:

    后台代码

     通过刷新页面我们可以看到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文件,随意在文件中添加些内容。然后创建页面,前台代码:

    前台代码

     后台代码:

    后台代码

     这个例子关联了两个文件,其中任何一个改变都会引起缓存的失效。

    以上这两个例子都实现了文件的缓存,但是有一个显著的不同。对于第一个例子,在缓存到期之前如果刷新了页面则缓存时间累加,也就是说页面不会更改,必须在缓存时间内没有刷新页面,过了缓存时间,缓存才会失效。对于第二个例子,不管在缓存时间内如何刷新页面,只要缓存到期,那么页面就会失效。

     

    (八)基于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 }
    复制代码
  • 相关阅读:
    gitlab搭建
    .NET Core 跨平台物联网开发:设置委托事件(二)
    .NET Core 跨平台物联网开发:连接阿里云IOT(一)
    Orange Pi 3 GPIO 笔记
    树莓派踩坑备忘录 -- 使用 Linux
    .NET Core / C# 开发 IOT 嵌入式设备的个人见解
    阿里云 IOT 对接设备开发 C# 开发设备对接阿里云 IOT平台
    跨平台开发 -- C# 使用 C/C++ 生成的动态链接库
    .NET Core 使用 EF 出错的解决方法
    arm 开发板更新 gcc/gcc++ | Debain 更新 gcc,无需编译直接更新 gcc
  • 原文地址:https://www.cnblogs.com/yelanggu/p/5338014.html
Copyright © 2020-2023  润新知