1. 缓存概述

使用缓存可以避免重新从读取服务器端读取数据,节省数据从客户端到服务器间往返的时间,同时也减轻了服务器数据存取的压力。

如果客户端非常频繁地读取服务器上的数据,比如生成报表,并且服务器每次获取这些数据都经过复杂的处理逻辑,那么就可能非常有必要使用缓存。

ASP.NET 使用两种基本的缓存机制来提供缓存功能。第一种机制是应用程序缓存,它允许您缓存所生成的数据,如 DataSet 或自定义报表业务对象。第二种机制是页输出缓存,它保存页处理输出,并在用户再次请求该页时,重用所保存的输出,而不是再次处理该页。

 

2. Asp.net 2.0 支持的几种类型缓存

2.1 页面输出缓存

使用页面输出缓存就是指内存中缓存asp.net页面的内容,这样每次需要这些内容都无需重新生成,取而代之的是从内存中直接读取,这样节省了asp.net页面控件生成这些内容的时间,从而大大地提高了应用程序的性能。如果客户访问的这些页面的内容不经常变化,这些页面的访问量较大,那么就非常适宜使用页面输出缓存。

2.1.1 全局页面缓存

全局页面缓存是指将整个页面的内容都缓存在内存中供客户端调用。

举例:

我们访问如下的情形时,就可以使用全局页面缓存:

 

http://localhost/mypage.aspx?categoryid=foo

http://localhost/mypage.aspx?categoryid=foo

 

  

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%>

<%@ OutputCache Duration="10" VaryByParam="categoryid" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

<form id="form1" runat="server">

    <div>

<%Response.Write(System.DateTime.Now);%>

    </div>

</form>

</body>

</html> 


 

 

运行程序,输出内容为8/31/2010 3:24:38 PM

如果10秒以内不改变categoryid的值,再次刷新页面,则输出内容依然是:

输出内容为8/31/2010 3:24:38 PM

如果10秒以内改变categoryid的值,再次刷新页面,则输出内容依然是:

输出内容改变为当前时间:8/31/2010 3:24:39 PM

 

这里VaryByParam可供选择的有none,*或多个参数(categoryid; categoryname…).

 

 

2.1.2页面片断缓存

 

而页面片断缓存是指在内存中缓存部分页面的内容,而其他的部分是动态重新生成的。

页面部分缓存的实现包括两种方式:控件缓存和替换后缓存。前者也可称为片段缓存,这种方式允许将需要缓存的信息包含在一个用户控件内,然后,将该用户控件标记为可缓存的,以此来缓存页面输出的部分内容。这一方式缓存了页面中的特定内容,而没有缓存整个页面,因此,每次都需重新创建整个页。例如,如果要创建一个显示大量动态内容(如股票信息)的页,其中有些部分为静态内容(如每周总结),这时可以将静态部分放在用户控件中,并允许缓存这些内容。缓存后替换与控件缓存正好相反。这种方式缓存整个页,但页中的各段都是动态的。例如,如果要创建一个在规定时间段内为静态的页,则可以将整个页设置为进行缓存。如果向页添加一个显示用户名的Label控件,则对于每次页刷新和每个用户而言,Label的内容都将保持不变,始终显示缓存该页之前请求该页的用户的姓名。使用缓存后替换机制,可以将页配置为进行缓存,将页的个别部分标记为不可缓存。在此情况下,可以向不可缓存部分添加Label控件,这样将为每个用户和每次页请求动态创建这些控件。

举例:

设置页面片断缓存可以采用<%@ Control Language="C#" ClassName="WebUserControl" %><%@ OutputCache Duration="10" VaryByParam="*"%>

或者在类名前加特性[PartialCaching(3)]

如:

<%@ Control Language="C#" ClassName="WebUserControl" %>

<%@ OutputCache Duration="10" VaryByParam="*"%>

<script runat="server">

 

protected void Page_Load(object sender, EventArgs e)

    {

        this.Label1.Text = System.DateTime.Now.ToString("hh:mm:ss");

        this.timer.Style.Add("width", (DateTime.Now.Second * 4).ToString() + "px");

    }

 

</script>

 

<div id = "timer" runat="server" style="background-color:Cyan;">

<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

</div>


[PartialCaching(3)]


public partial class WebUserControl3 : System.Web.UI.UserControl

{

    protected void Page_Load(object sender, EventArgs e)

    {

        this.Label1.Text = System.DateTime.Now.ToString("hh:mm:ss");

        this.timer.Style.Add("width", (DateTime.Now.Second * 4).ToString() + "px");

    }

}

 


 

 

2.2   应用程序数据缓存

 

ASP.NET 提供一个功能完整的缓存引擎,页面可使用该引擎通过 HTTP 请求存储和检索任意对象。ASP.NET 缓存对于每个应用程序是私有的并且将对象存储在内存中。缓存的生存期与应用程序的生存期相同,也就是说,当应用程序重新启动时,将重新创建缓存。

 

缓存提供了简单的词典接口,使程序员可以轻松地将对象放到缓存中以及从缓存中检索对象。在最简单的情况下,将某项放到缓存中就像向词典中添加一个词条一样。

 

示例,建立一个缓存xml文件的应用程序如下[下载源代码https://files.cnblogs.com/Ring1981/Cache.rar]:

 

1 建立default.aspx页面

<%@ Page Trace="true" TraceMode="SortByCategory" Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

 

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<body>

    <form id="form1" runat="server">

    <div>

        <asp:Button ID="Button1" runat="server" Text="Flush Cache" OnClick="Button1_Click" />

    <asp:DataGrid ID="dg1" runat="server"/>

    </div>

    </form>

</body>

</html>

 

2 添加一个names.xml

<?xml version="1.0" encoding="utf-8" ?>

<people>

 <person first="Scott" last="stafield"></person>

 <person first="jim" last="Green"></person>

 <person first="kate" last="Green"></person>

</people>

 

3.添加后台代码

public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!Page.IsPostBack)

        {

            DataSet ds = null;

            ds = (DataSet)Cache["names"];

 

 

            if (ds == null)

            {

                string path = @"c:\names.xml";

                ds = new DataSet();

                ds.ReadXml(path);

                CacheDependency cd = new CacheDependency(path);

                Cache.Insert("names", ds, cd);

                Trace.Warn("Names read from XML file");

            }

            Else

            {

                Trace.Warn("Names read from cache");

            }

            dg1.DataSource = ds;

            dg1.DataBind();

        }

    }

 

protected void Button1_Click(object sender, EventArgs e)

    {

       Cache.Remove("names");

        Response.Redirect("default.aspx");

    }

}


 

运行程序, 第一次运行时,DataGrid里的数据是从xml文件中读取的。 以后每次刷新,文件都是从缓存读取的。

我们可以从每次运行时间看到:

每次读取xml花费时间大约0.001275s,

每次读取缓存花费时间大约 0.000044s

 

2.3   缓存的命中率

 

一个缓存的实体在被丢到缓存中后,在这个实体被缓存的期间(这个实体被缓存的生命周期内),如果外部一次都没有使用过它,这个缓存实体的命中率就是0。这个实体被请求的次数越多,它的缓存命中率越高。

 

2.3.1   提高缓存命中率的一些常见方法

 

1.     小型网站可以全部数据缓存,一般压力也不会很大,可以忽略缓存命中率问题。

2.     大型服务无法全部数据缓存,只能部分数据缓存,这时候就需要架构师设计出对该业务逻辑适用的缓存方法,尽可能的提高缓存的命中率。

3.     提高命中率的方法大多是跟业务逻辑捆绑的,需要跟具体问题具体分析。

4.     对于不能被内存缓存的数据,最简单的提高性能方法就是使用文件缓存。

5.     文件缓存可以整个内容缓存成一个静态文件;也可以是整个页面的一个区域被缓存成一个文件,然后被包含;也可以是把一个实体序列化成XML文件进行缓存。

 

 

 

 

2.4 缓存依赖

 

CacheDependency 类监视依附性关系,以便在任何这些对象更改时,该缓存项都会自动移除。

 

2.4.1 文件依赖:

 

如果向缓存添加一个依赖于另一个对象(如文件或文件数组)的项,则在该对象更改时会自动从缓存中移除该依赖项。例如,假设您基于 XML 文件中的数据创建一个 DataSet 对象。可以利用使 DataSet 依赖于 XML 文件的 CacheDependency 对象将该 DataSet 添加到缓存中。如果该 XML 文件发生更改,则 DataSet 从缓存中移除。

 

2.4.2 数据库表依赖:

SqlCacheDependency 类在所有受支持的 SQL Server 版本 (7.0, 2000, 2005) 上监视特定的 SQL Server 数据库表,以便在该表发生更改时,自动从 Cache 中删除与该表关联的项

 

数据库表发生更改时,将自动删除缓存项,并向 Cache 中添加新版本的项。

 

在使用 SQL Server 2005 数据库时,SqlCacheDependency 类还支持与 System.Data.SqlClient.SqlDependency 类进行集成。使用 SQL Server 2005 的查询通知机制来检测使 SQL 查询结果无效的数据更改。与 SQL 查询关联的任何缓存项都将从 System.Web.Caching.Cache 中移除。

 

SqlCacheDependcy参数配置说明分三步

 

1.配置数据库支持sqlCacheDependcy(Sql 2000, 2005)

 

window验证

aspnet_regsql -S ServerName -E -d pubs -ed

aspnet_regsql -S ServerName -E -d pubs -t authors -et

aspnet_regsql -S ServerName -E -d pubs -lt

 

说明:

-S 连接到哪个数据库实例

-E 连接数据库采用的连接方式

-d 数据库明

-ed为数据库启动该特性支持

 

sql验证

aspnet_regsql -S ServerName -U username -P password -d databasename -ed -et -t tablename

 

 2.Web应用程序

<%OutputCache Duration="600" varybyparam="none" sqldependency="database.tablename"%>

SqlDataSource:

GridView:

database.tablename:WebConfig中会有所配置

 

3.配置WebConfig

 

<ConnectionStrings>

 <add name = "pubsConnectionString" value=""">

</ConnectionStrings>

<cache>

   <sqlCacheDependency enable="true" pollTime="1000">

       <databases>

           <add name="databasename" connectionString="pubsConnectionString"/>       </databases>

   </sqlCacheDependcy>

</cache>

 

2.4.3 AggregateCacheDependency

 

AggregateCacheDependency 类监视依赖项对象的集合,以便在任何依赖项对象更改时,该缓存项都会自动移除。数组中的对象可以是 CacheDependency 对象、SqlCacheDependency 对象、从 CacheDependency 派生的自定义对象或这些对象的任意组合。

AggregateCacheDependency 类与 CacheDependency 类的不同之处在于前者允许您将不同类型的多个依赖项与单个缓存项关联。例如,如果您创建一个从 SQL Server 数据库表和 XML 文件导入数据的页,则可创建一个 SqlCacheDependency 对象来表示数据库表的依赖项,以及一个 CacheDependency 来表示 XML 文件的依赖项。可创建 AggregateCacheDependency 类的一个实例,将每个依赖项添加到该类中,而不是为每个依赖项调用 Cache.Insert 方法。然后,可使用单个 Insert 调用使该页依赖于 AggregateCacheDependency 实例。