zoukankan      html  css  js  c++  java
  • 深入System.Web.Caching命名空间 教你Hold住缓存管理

    一,System .Web.Caching与缓存工作机制简介

      System.Web.Caching是用来管理缓存的命名空间,其父级空间是System.Web,由此可见,缓存通常用于Web网站的开发,包括在B/S项目中的开发。

      缓存的设计主要是考虑到网络带宽可能会延缓数据的提交与回发,如果把数据保存在客户端,用户就可以直接从客户端读取数据,减少客户端与服务器端的数据交互,提高程序的性能。

      缓存命名空间中的类及其说明:

    • Cache 对缓存对象的编辑类,其操作包括缓存的增删改
    • CacheDependency 基本缓存对象的依赖,当基本对象发生变化时,更新缓存内容
    • SqlCacheDependency 数据库缓存对象的依赖,当数据库中的数据发生变化时,更新缓内容

      其中,缓存任何对象都使用类Cache,但当缓存发生改变时,普通对象与数据库对象的依赖处理不同,分别对应以上两个依赖。

      下图展示了三层结构中缓存的工作机制:

      

    二,管理缓存的类:Cache

      1.功能说明

      Cache类属于字典类(键-值对),其根据一定的规则存储用户需要的数据,这些数据的类型不受限制,缓存的数据可以是字符串,数组,数据表,自定义类等等。

      使用Cache类的优点是当缓存的数据发生变化时,Cache类会让当前缓存数据失效,并实现缓存数据的重新添加,然后通知应用程序,报告缓存的及时更新。

      2.语法定义

      Cache类的语法定义如下:

    public sealed class Cache : IEnumerable

      

      通过定义发现,Cache类是sealed密封的类,不能被集成。同时Cache继承了IEnumerable接口,允许对集合中的数据进行枚举操作。

      缓存的生命周期随着应用程序域的活动结束而终止,也就是说只要应用程序域依然出于活动状态,缓存就一直会保持,因为每个应用程序域都会创建一个缓存实例。此实例的信息可以通过HttpContext对象,Page对象的Cache属性获取。

      3.方法详解

      Cache类的方法主要提供对缓存数据的编辑操作:

    • Add 将数据添加到Cache对象
    • Insert 向Cache中插入数据项,可用于修改已经存在的缓存数据项
    • Remove 移除Cache对象中的缓存数据项
    • Get 从Cache对象中获取指定的数据项,注意返回的是Object类型,需要进行类型转换。
    • GetType 从Cache对象中获取数据项的类型,判断数据类型后方便进行类型转换。
    • GetEnumerator 循环访问Cache对象中的缓存数据项,其返回类型是"IDictionaryEnumerator"

      最需要注意的是Add方法的参数,其使用语法如下:

    public object Add(
    string key, object value, CacheDependency dependencies,
    DateTime absoluteExpiration, TimeSpan slidingExpiration,
    CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback
    );
    • key:表示缓存数据项的键值Key,必须是唯一的。
    • value:要添加到缓存的项。可以是任意的类型。
    • dependencies:表示缓存的依赖项,此项发生变化时就意味着缓存内容已经过期,并从缓存中移除。如果没有依赖项,则此值设置为null。
    • absoluteExpiration:绝对到期,所添加对象将到期并被从缓存中移除的时间。
    • slidingExpiration:可调到期,最后一次访问所添加对象时与该对象到期时之间的时间间隔。如果该值等效于20分钟,则对象在最后一次被访问20分钟之后将到期并从缓存中移除。
    • priority:撤销缓存的优先值,由System.Web.Caching.CacheItemPriority枚举表示。缓存在退出对象时使用该值,优先级低的数据项先被删除。
    • onRemoveCallback:表示缓存删除数据对象时调用的时间,一般用作通知程序。

      特别有一点要提一下,绝对到期和可调到期只能指定一个,

      使用绝对到期,则可调到期值必须为System.Web.Caching.Cache.NoSlidingExpiration,禁用可调到期。

      反之,使用可调到期,则绝对到期的值必须为System.Web.Caching.Cache.NoAbsoluteExpiration,禁用绝对到期。

      Insert方法和Add方法的参数是一样的,不过Insert方法提供了更多的重载,如果你不提供某个值,那这个值就会被设置为默认值。

      下面的例子演示了Cache的基本用法:

    复制代码
     public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                Cache["League"] = "NBA";//指定了Key与Value,其他参数均为默认值
                Cache["League"] = "CBA";//更新缓存项内容方法,同上
                ArrayList player = new ArrayList();
                player.Add("JohnConnor");
                player.Add("YaoMing");
                player.Add("KobeBryant");
                //使用Add方法新增一个缓存项,Key为"Player",值为player对象,可调到期10分钟,优先级Normal,无回调委托
                Cache.Add("Player", player, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10), CacheItemPriority.Normal, null);
                player[0] = "MichaelJordan";
                Cache.Insert("Player", player);//Insert方法可以用来插入缓存项或更新其内容,这里使用了最简单的重载
                Response.Write(Cache["Player"].GetType().Name + "</br>");//GetType方法可以来获取缓存项内容的类型
                Response.Write(Cache.Get("League").ToString() + "</br>");//Get方法来根据Key获取Value
                IDictionaryEnumerator mycache = Cache.GetEnumerator();//使用GetEnumerator方法来遍历缓存项
                while (mycache.MoveNext())
                    Response.Write(mycache.Key + "</br>");
                Cache.Remove("League");//移除Key为"League"的缓存项
            }
        }
    复制代码

      

      代码中使用了ArrayList,所有别忘记了添加”System.Collections“命名空间的引用,当然使用Cache,别忘记了添加”System.Web.Caching“.

      4.属性详解

      Cache类的属性主要用来获取缓存数据的一些基本信息,这里主要介绍Count和Item属性。

      Count用来获取缓存中所有缓存项的总数:

    Response.Write(Cache.Count);//缓存项总数

      Item用于返回制定项的内容,前面其实已经演示过了,一般继承”IEnumerable“接口的类都有这样的属性,使用[]来包装,用法如下:

    Response.Write(Cache["League"]);

     

    三,典型应用,实现数据缓存的快速读取

      Cache主要用来缓存使用频率高且不需经常更新的数据。我们来做一个球员列表的缓存,为了演示方便,假设不从数据库中读取数据,而是存在一个ArrayList对象中。

      1.首先在打开VisualStudio创建一个ASP.NET网站,命名为”JohnConnor.CacheSample“。

      2.打开默认生成的Default.aspx页,在设计视图中添加一个下拉列表框和一个按钮。

      3.切换到页面的代码视图,不要忘记添加命名空间的引用喔。

    using System.Collections;
    using System.Web.Caching;

      4.在”Page_Loda“事件中判断是否存在球员列表缓存,如果没有,则将球员列表添加到缓存中。详细代码如下:

    复制代码
     protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                {
                    ArrayList player = new ArrayList();
                    player.Add("JohnConnor");
                    player.Add("YaoMing");
                    player.Add("KobeBryant");
                    if (Cache["Player"] == null)//如果没有缓存就添加缓存
                    {
                        Cache.Add("Player", player, null, Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(10), CacheItemPriority.Normal, null);
                    }
                }
            }
    复制代码

      

      5.然后我们在按钮的双击事件中判断是否有球员列表的缓存,有则显示列表内容,没有则清空下拉框:

    复制代码
     protected void Button1_Click(object sender, EventArgs e)
            {
                if (Cache["Player"] != null)//判断缓存是否失效
                {
                    //缓存未失效则取出球员列表缓存
                    DropDownList1.DataSource = Cache["Player"] as ArrayList;
                    DropDownList1.DataBind();
                }
                else
                {
                    DropDownList1.Items.Clear();//缓存失效则清空列表
                }
            }
    复制代码

      现在F5运行程序,因为我们设定的是可调到期10秒,可就是说距离最后一次访问10秒后,缓存就会失效。

      我们在一开始10秒内点击按钮,球员列表就会被绑定到下拉框。

      但之后的10秒内无动作,再点击的话,下拉框就会被清空。因为缓存已经失效了。

      这一篇是缓存管理的第一篇,我们介绍了System.Web.Caching命名空间和其下Cache类的使用方法,并没有涉及缓存依赖的内容。

      当实际数据改变的时候,如果缓存不发生改变,那是很糟糕的事情,随后的两篇将会介绍通过依赖项来实现缓存数据的即时更新。希望大家捧场。

    在学习了第一篇Cache类的用法后,下面我们来继续看看如果缓存从文件中读取的的数据,并通过缓存依赖类CacheDependency实现缓存数据的及时更新。

    一,缓存依赖类CacheDependency

      CacheDependency类是架设在Cache类和实际数据之前的桥梁,其具体的意义是当缓存对象的实际数据发生改变的时候,它能及时的通知缓存对象。

      假如缓存对象”Player“保存的是一个XML文件的数据,如果XML文件发生了变化,那么系统通过CacheDependency类就会及时的更新缓存对象的内容,保证用户读取的永远是最新的数据。

      1.语法定义

      CacheDependency类的语法定义如下:

    public class CacheDependency : IDisposable

      继承了接口”IDisposable“,此接口主要用来定义释放分配的非托管资源的方法。继承此接口的类,必须实现方法Dispone ,实现资源的释放。

      继承这个接口有什么好处呢,看下面一段代码:

        using (CacheDependency mydep = new CacheDependency("player.xml"))
        {
            //dosomething 
        }

      这样使用using来创建一个新对象,在出了这个作用域之后,即”{}“内的代码执行完毕,系统就会自动调用Dispone来释放该对象占用的资源。

      经常打开数据库链接又懒得去显式关闭的同学,对此应该比较熟悉。

      CacheDependency类构造函数实现了8个对外公开的重载,虽然全部列出麻烦了点,但为了知道CacheDependency究竟能为缓存带来什么优势,我们来细说一下每个重载。

    复制代码
    1 public CacheDependency(string filename);
    2 public CacheDependency(string[] filenames);
    3 public CacheDependency(string[] filenames, string[] cachekeys);
    4 public CacheDependency(string filename, DateTime start);
    5 public CacheDependency(string[] filenames, DateTime start);
    6 public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency);//dependency参数声明此依赖项依赖另外一个CacheDependency的实例
    7 public CacheDependency(string[] filenames, string[] cachekeys, DateTime start);
    8 public CacheDependency(string[] filenames, string[] cachekeys, CacheDependency dependency, DateTime start);
    复制代码

      (1)监视文件或目录<参数filename>更改情况,当该资源发生变化时,与此依赖项对象关联的缓存对象将过期,并从缓存中移除。

      (2)监视一组文件或目录<参数filenames>更改情况,当这些资源中任何一个变化时,处理同上。

      (3)监视一组文件或目录<参数filenames>的同时,也监视一组缓存键<参数cachekeys>的更改情况,当这些资源中任何一个变化时,处理同上。

      这三个是最基本的构造函数,其他的重载只是声明了此依赖项所依赖另外一个CacheDependency的实例<参数dependency>,

      或是监视对象上次修改日期所依据的日期和时间<参数start>。

      2.方法和属性

      CacheDependency的组成结构与它重要的功能比起来,较为简单。主要有两个属性和一个方法:

    • 属性”HasChanged“:判断CacheDependency对象是否已更改。
    • 属性”UtcLastModified“:返回上次依赖项的修改日期。
    • 方法”Dispose“:释放CacheDependency对象占用的资源。

      我们在最后的应用的例子中来了解这些属性和方法的使用。

    二,典型应用:用CacheDependency获取最新的数据

      我们这里需要使用CacheDependency类来实现数据的及时更新。演示中使用GridView来显示一个XML文件的数据,当XML文件数据发生改变时,客户端可以及时更新。

      先来看下实现的过程图解:

      

      下面我们来实现这个过程。

      1,首先我们使用VisualStudio创建一个ASP.NET网站,命名为”JohnConnor.CacheDependencySample“,并在根目录下添加一个文件名为players的XML文件:

    复制代码
    <?xml version="1.0" encoding="utf-8" ?>
    <playerslist>
        <player>
            <name>KobeByrant</name>
            <height>1.98m</height>
        </player>
        <player>
            <name>AllenIverson</name>
            <height>1.83m</height>
        </player>
    </playerslist>
    复制代码

      2,我们打开默认生成的Default .aspx页,在设计视图中添加一个GridView和按钮和一个Label控件。然后在代码视图的Page_Load事件中添加生成缓存的代码:

    复制代码
     private static CacheDependency mydepen;
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                {
                    DataSet myds = new DataSet();//创建XML数据源
                    myds.ReadXml(this.MapPath(Request.ApplicationPath + @"/players.xml"));//数据源来自文件players.xml
                    if (Cache["Players"] == null)//判断缓存是否存在
                    {
                        mydepen = new CacheDependency(this.MapPath(Request.ApplicationPath + @"/players.xml"));//创建缓存依赖
                        //添加缓存项
                        Cache.Add("Players", myds, mydepen, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10), CacheItemPriority.Normal, null);
                    }
                }
            }
    复制代码

      3,最后我们在按钮的Click事件里判断实际数据是否被修改,如果修改则重新生成缓存和依赖,并绑定数据:

    复制代码
     protected void Button1_Click(object sender, EventArgs e)
            {
                if (mydepen.HasChanged)//判断实际数据是否发生了变化
                {
                    Label1.Text="球员列表已经改变,上一次修改时间:" + mydepen.UtcLastModified;
                    DataSet myds = new DataSet();//创建XML数据源
                    myds.ReadXml(this.MapPath(Request.ApplicationPath + @"/players.xml"));//数据源来自文件players.xml
                    mydepen = new CacheDependency(this.MapPath(Request.ApplicationPath + @"/players.xml"));//重新创建缓存依赖
                    //重新添加缓存项
                    Cache.Add("Players", myds, mydepen, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10), CacheItemPriority.Normal, null);
                }
                GridView1.DataSource = Cache["Players"];
                GridView1.DataBind();
            }
    复制代码

      现在F5运行,点击按钮就会得到XML文件中的数据:

      

      然后我们对XML文件进行修改,添加一个球员,点击按钮,就会刷新缓存,显示最新的数据:

      

      虽然我的名字出现在这里有点突兀哈哈,请大家不要喷我。

      这一篇我们解决了使用文件依赖来进行缓存及时更新的问题。

      下一篇我们要解决的问题是当数据库内容发生改变时,如何及时通知缓存,并更新缓存中的数据,请大家多多支持。

    在学习了前两篇Cache类和CacheDependency类的用法后,最后一篇,我们来玩一下SqlCacheDependency类实现数据库缓存的及时更新。

    如果对缓存管理没有基础的看官,建议看完前两篇再来看这一篇。

    一,数据库缓存依赖类SqlCacheDependency

      SqlCacheDependency类的使用需要结合SQL Server数据库,目前还没有Oracle数据库的缓存依赖。此篇我们使用SQL Server2005来演示。

      1.语法定义

      SqlCacheDependency类的语法定义如下:

    public class SqlCacheDependency: IDisposable

      同CacheDependency类一样,SqlCacheDependency也继承了接口”IDisposable“,此接口主要用来定义释放分配的非托管资源的方法。

      继承此接口的类,必须实现方法Dispone ,实现资源的释放。这个接口在第二篇中有稍作介绍,在此不再复述了。

      SqlCacheDependency的主要构造函数如下:

    public SqlCacheDependency(string dataBase,string table)

      dataBase代表要启用的缓存的数据库,table代表缓存的表。实际使用过程中,只需要指明缓存的数据和表就可以了。

      2.方法和属性

      SqlCacheDependency类的方法和属性与CacheDependency类相同,主要还是那三个:

    • 属性”HasChanged“:判断数据库依赖是否发生了变化。
    • 属性”UtcLastModified“:获取数据库缓存依赖项上次更改的事件。
    • 方法”Dispose“:释放SqlCacheDependency对象占用的资源。

      这三个成员的使用方法同CacheDependency类的成员相似,所以在此不再赘述。有需要的话可以在参考第二篇。

    二,使用SqlCacheDependency类的流程

      实现数据库缓存依赖,我所知的方法有两种,一种是使用编程的方法来实现,与第二篇中的实现文件缓存依赖的思路相似,不过创建缓存时依赖项是SqlCacheDependency的一个实例。

      所以这里我想介绍给大家的是OutputCache缓存技术。如果想使用编程方式来实现此功能,可参考第二篇中最后的示例。

      要实现数据库缓存依赖,必须结合数据库的操作。在使用数据库缓存依赖之前,必须进行5步操作:

      

      只有具备了上述条件,才可以正常的使用数据库缓存依赖。最后我们看看如何来实现。

    三,典型应用:使用SqlCacheDependency获取数据库表最新数据

      这个示例所体现的功能是,缓存数据库表,并在内容发生变化时,保存在缓存中的数据项更新到最新。

      1,创建数据库并为

      我们首先创建一个数据库JohnConnor_DB,然后在数据库中添加一个Player表:

    • id <int> 自增长数据标识,
    • Name <nvarchar(20)>  球员姓名,
    • Height<nvarchar(10)> 球员身高

      2,通知数据库启用缓存依赖项

      SQLServer支持SqlCacheDependency特性,需要对数据库服务器执行相关的配置。

      现在我们来为数据库启用缓存通知。这里有两种方式来通知数据库,表启用缓存依赖项,

    • 借用ASPNET_REGSQL命令行工具
    • 使用SqlCacheDependencyAdmin类

       首先我们来介绍使用命令行工具,该工具位于windowsmicrosoft.netframework[版本]文件夹中。如果你找不到它,在安装VS2005以上版本的前提下,

      可以点击 开始/所有程序/MicroSoft Visual Studio 2010/Visual Studio Tools/Visual Studio 2010命令提示来使用它,在命令提示框中输入

    aspnet_regsql.exe -S 192.168.1.99sqlserver2005 -U (JohnConnor),-P (JohnConnorV5) -ed -d JohnConnor_DB -et -t Player

      注意如果使用的数据库验证方式是"Sql Server身份验证",则需要-E换成,

      如果你想了解上面每个命令参数的意义,可以输入aspnet_regsql.exe -? 这里为了方便大家理解给了个参数列表(列表是COPY来的,原谅我的懒惰,阿门~~~)

    • -S 后接的参数为数据库服务器的名称或者IP地址;
    • -U 后接的参数为数据库的登陆用户名;
    • -P 后接的参数为数据库的登陆密码;
    • -E 使用当前登录用户的 Windows 集成认证进行身份验证。
    • -d 后接参数为对哪一个数据库采用SqlCacheDependency功能;
    • -C 连接数据库的连接字符串。如果您指定服务器(-S)和登录(-U和-P,或 -E)信息,则此选项不是必需的,因为连接字符串已经包含这些信息。
    • -t 后接参数为对哪一个表采用SqlCacheDependency功能;
    • -ed 允许对数据库使用SqlCacheDependency功能;
    • -dd 禁止对数据库采用SqlCacheDependency功能;
    • -et 允许对数据表采用SqlCacheDependency功能;
    • -dt 禁止对数据表采用SqlCacheDependency功能;
    • -lt 列出当前数据库中有哪些表已经采用sqlcachedependency功能。

      输入命令后,回车,执行成功,会提示为SQL缓存依赖项启用该数据库/表。

      第二个方法使用SqlCacheDependencyAdmin类,直接在页面的“Page_Load”下加入以下注册代码

    复制代码
      protected void Page_Load(object sender, EventArgs e)
        {   
         System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(
      System.Configuration.ConfigurationManager.ConnectionStrings["name"].ConnectionString);//通知哪个数据库,name是该数据库链接字符串的名字 System.Web.Caching.SqlCacheDependencyAdmin.EnableTableForNotifications(
      System.Configuration.ConfigurationManager.ConnectionStrings["name"].ConnectionString, "Player");//通知启用哪个表,Player是表名 }
    复制代码

      就可以了。

      两种方法执行后,会向数据库里添加一个AspNet_SqlCacheTablesForChangeNotification表。

      3,在网站中进行数据库缓存项配置

      然后我们新建一个ASP.NET网站(我偷懒,第二篇的改个名字继续用...),命名为JohnConnor.SqlCacheDependencySample。

      首先我们在Web.Config中配置数据库链接字符串:

     <connectionStrings>
            <add name="TestDBconnectionStrings" providerName="System.Data.SqlClient" 
          connectionString="Data Source=192.168.1.99SQLSERVER2005;Initial Catalog=JohnConnor_DB;User ID=JohnConnor;Password=JohnConnorV5;" /> </connectionStrings>

      然后在“system.web”节点内,添加数据库缓存依赖的配置,注意配置中的“connectionStringsName”属性,需要与前面创建的数据库链接字符串名字对应:

    复制代码
      <caching>
           <sqlCacheDependency enabled="true" pollTime="1000">
               <databases>
                   <add name="JohnConnor_DB" connectionStringName="TestDBconnectionStrings" pollTime="1000"/>  
                    </databases>
           </sqlCacheDependency>
       </caching>
    复制代码

      现在我们的配置部份就暂时告一段落。下面我们来验收成果。

      4. 完成示例

      我们在默认生成的Default.aspx页,添加一个GridView控件,用来显示从数据库获取的数据。并添加一个控件,主要用来显示时间,用时间来判断页面显示的是否是缓存数据。

      首先给GridView配置数据源,单击任务列表,在“选择数据源”下拉框中,单击“新建数据源”,在配置向导的数据源类型窗口中选择“数据库”,单击“确定”后出现选择链接字符串窗口,在下拉列表中选择我们刚才创建的”TestDBconnectionStrings“连接串,单击”下一步“,出现“配置Select语句”对话框,在“列”列表框中选择“*”,表示选中所有列,”下一步“,“完成”。

      现在切换到代码视图,在"Page_Load"事件中添加:

    Literal.Test=DateTime.Now.ToString();

      主要是来判断显示的是不是缓存。现在保存下F5,刷新页面可以看到时间是不断变化的,说明数据并非来自缓存。

      现在在Default.aspx的源代码视图的"<@page>"行下,添加如下代码:

    <%@ OutputCache Duration="3600"  SqlDependency="JohnConnor_DB:Player" VaryByParam="none"%>

      这样数据库缓存依赖就添加完成了。

      现在F5运行网站,此时再刷新页面,发现时间已经不再变化,因为整个页的数据都被缓存了。

      现在我们修改以下数据库的内容,然后刷新刚才的页面,可以发现,时间向后推进了,数据也发生了改变。

      这就是数据库缓存依赖的作用了。

      当数据库内容更新的时候,不管缓存的时间是否到了,缓存内容都会被更新。

      ----------------------------------------------------------END------------------------------------------------------

      草草结了个尾。。。

      至此,三篇已经完结。这是一个完结的短篇幅系列,,,不容易呢。比较忙丫,没时间写长篇。

      谢谢大家捧场。希望能够帮助到有用的人。

  • 相关阅读:
    176. Second Highest Salary
    175. Combine Two Tables
    172. Factorial Trailing Zeroes
    171. Excel Sheet Column Number
    169. Majority Element
    168. Excel Sheet Column Title
    167. Two Sum II
    160. Intersection of Two Linked Lists
    个人博客记录
    <meta>标签
  • 原文地址:https://www.cnblogs.com/zjoch/p/4778631.html
Copyright © 2011-2022 走看看