【.NET全栈】ASP.NET开发Web应用——缓存技术


前言

缓存技术是指在内存中存储哪些需要频繁操作和访问的数据,以提高应用的性能。在ASP.NET中可能最影响速度的操作就是访问数据库。

首先需要与数据库建立连接、打开数据表查询数据、向客户端返回数据,这些操作将会显著地影响服务器端的性能。

对于一些更新不频繁的或者是数据量很大的操作,频繁的操作会导致消耗大量服务器资源,最好的方法是使用缓存来提高应用程序的性能。

本章要学习的主要内容有:

  • 理解APS.NET缓存技术
  • 输出缓存
  • 缓存数据
  • 缓存依赖技术

一、理解ASP.NET缓存技术

很多开发人员排斥或极少使用缓存,认为缓存只是一种装饰,这是一种错误的见解。灵活地使用缓存能有效地提高应用程序的性能,ASP.NET提供了大量的缓存API和多种缓存机制,极大地简化了创建灵活缓存的复杂性。

ASP.NET中有两种类型的缓存机制,一种是输出缓存,一种是数据缓存。

  • 输出缓存(Output caching)

输出缓存是一种简答的缓存机制,它将输出到客户端的HTML页面进行缓存,当其他用户继续请求页面时,服务器端将直接从内存中取出缓存的页面,而不用历经一遍的ASP.NET的页面生存周期。页面输出缓存对于那些不经常更改,但需要大量处理才能创建的页特别有用。

例如,如果创建大通信量的网页来显示不需要频繁更新的数据,页输出缓存则可以极大地提高该页的性能。

  • 数据缓存(Data caching)

又称应用程序缓存,这种类型的缓存需要手工编写程序代码来实现。比如可以将动态生成的DataSet对象添加到一个缓存对象中,后继的用户使用该对象时,可以判断缓存中是否存在缓存的对象,如果存在则直接使用缓存对象,否则创建一个全新的对象并进行缓存。

输出缓存提供了简介的办法缓存整页或者是部分页面,输出缓存又分为两种类型:

  • 整页缓存

这种方式将页的全部内容保存在内存中,在客户端请求该页面时并返回整个页面的缓存。

  • 部分页缓存

又称为分段缓存,这种方式可以只缓存页面中的部分内容,并不缓存整个页面。

还有一种非常重要的缓存类型:数据缓存
每种DataSource控件都内置了缓存机制,可以减少应用程序请求数据库的过程。

二、输出缓存

输出缓存将缓存最终输出的HTML内容,当用户再次请求相同的页面时,页面将不会重新经过页面生命周期重新创建一次。从理论上来说,输出缓存能够提供最大的性能增强。

1、定义输出缓存

输出缓存将缓存最终输出的HTML内容,当用户再次请求相同的页面时,页面将不会重新经过生命周期重新刷新一次。

从理论上来说,输出缓存能够提供最大的性能增强。

【范例】新建一个名为CachingDemo的网站,然后创建一个PageCaching.aspx网页。在PageCaching页面上放置一个Label控件和一个Button控件,在Page_Load事件中添加如下程序代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CachingDemo
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Label1.Text = "现在的时间是<br/>" + DateTime.Now.ToString();
        }
    }
}

在这里插入图片描述

在页面加载事件中获取当前服务器端的时间,每当请求页面时,都将产生不同的时间输出。现在看看为页面添加缓存后的效果。

要实现页面输出缓存,可以在页面声明区中添加一条OutputCache的声明,以声明的方式设置页面的缓存。代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CachingDemo.Default" %>
<%@ OutputCache Duration="5" VaryByParam="None" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
            <asp:Button ID="Button1" runat="server" Text="刷新" />
        </div>
    </form>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

【代码解释】当以声明的方式设置缓存时,至少都需要Duration和VaryByParam这两个属性。

Duration属性用于指定当前页面要缓存的时间,以秒为单位。本示例指定为5秒,当5秒过后再次请求该页面时,将获取到最新时间。VaryByParam表示根据指定的查询字符串来缓存页面,在下一小结将会详细讨论,None表示不会根据查询字符串缓存。

运行这个示例程序,页面再次被请求时将被缓存,如果此时连续电机刷新按钮,则页面不会发生任何变化,这是因为后续的请求将从ASP.NET服务器端缓存获取数据。5秒以后,缓存过期,将从ASP.NET缓存中移除对该页的请求。如果再次请求页面则再次缓存,5秒后又再次移出缓存。

2、查询字符串缓存

使用VaryByParam属性可以缓存指定查询字段串的页面,可能包括“NONE”、“*”、以及任何有效的查询字符串或POST参数名。

在一些场合下,使用VaryByParam属性非常有必要。比如一般企业应用系统的产品信息表,这个表只在特定情况下才会发生变化,但是在很多场合都需要查看该表,如销售、财务、生产模块等模块都要有能够查看产品细节的功能。通常创建一个主从式页面,在主页面中显示产品编码,而从页面显示产品信息。借助于VaryByParam属性,可以对指定查询字符串变量的不同页面进行缓存。

VaryByParam属性设置为None时,表示不根据查询字符串缓存,通常用于静态页面中。

使用“*”则表示可根据任何查询字符串缓存。通常为VaryByParam指定一个特定的查询字符串,如果需要指定多个查询字符串,则使用分号分隔的字符串,如“ProductID;CategoryID”。

<%@ OutputCache Duration="600" VaryByParam="ProductID;CategoryID" %>

<!DOCTYPE html>
<html>
<head>
    <title>Product Details</title>
</head>
<body>
    <h1>Product Information</h1>
    <% 
        // 假设从数据库中获取产品信息的代码如下:
        int productId = int.Parse(Request["ProductID"]);
        int categoryId = int.Parse(Request["CategoryID"]);
        Product product = GetProductFromDatabase(productId, categoryId);

        // 输出产品信息
        if (product != null) {
            %> 
            <p><strong>Product Name:</strong> <%= product.Name %></p>
            <p><strong>Product Description:</strong> <%= product.Description %></p>
            <p><strong>Category:</strong> <%= product.Category %></p>
            <p><strong>Price:</strong> $<%= product.Price %></p>
            <% 
        } else {
            %> 
            <p>No product found for the given ProductID and CategoryID.</p>
            <% 
        }
    %>
</body>
</html>

在上述代码中:

<%@ OutputCache Duration=“600” VaryByParam=“ProductID;CategoryID” %>, 这里的Duration="600"表示缓存持续时间为600秒(10分钟),VaryByParam="ProductID;CategoryID"表示页面缓存将根据ProductID和CategoryID这两个查询字符串参数来变化。

通过Request对象获取ProductID和CategoryID,并调用GetProductFromDatabase函数从数据库中获取相关产品信息。

根据获取的产品信息,动态输出产品名称、描述、类别和价格。如果产品不存在,则输出相应的提示信息。

通过这种方式,可以确保每次请求相同ProductID和CategoryID组合的用户都能从缓存中快速获取页面,提高应用性能和响应速度,同时确保数据的相对一致性。

3、自定义缓存

在ASP.NET中,Cache对象提供了一种存储和检索应用范围内的数据的机制。数据可以是任何对象,只要它实现了System.Web.SessionState.IHttpSerializable或System.Web.Caching.ICacheItem接口,或者是可序列化的。Cache对象存储的数据在应用程序域内是共享的,这意味着它对整个应用程序都是可访问的。

public class CacheExample
{
    private static readonly Cache _cache = HttpRuntime.Cache;

    // 存储数据到缓存中
    public void CacheData(string cacheKey, object data, int cacheTime)
    {
        CacheItemPolicy policy = new CacheItemPolicy();
        policy.AbsoluteExpiration = DateTime.Now.AddMinutes(cacheTime);
        _cache.Insert(cacheKey, data, null, policy.AbsoluteExpiration, TimeSpan.Zero);
    }

    // 从缓存中获取数据
    public object GetData(string cacheKey)
    {
        return _cache[cacheKey];
    }

    // 移除缓存中的数据
    public void RemoveData(string cacheKey)
    {
        _cache.Remove(cacheKey);
    }
}

初始化Cache对象:Cache _cache = HttpRuntime.Cache; 这行代码获取了ASP.NET的Cache对象,它提供了缓存功能。

存储数据:CacheData方法用于将数据存储到缓存中。它接受缓存的键、数据对象和缓存时间作为参数。通过CacheItemPolicy可以设置数据的过期时间。

获取数据:GetData方法通过缓存键来检索存储在缓存中的数据。

移除数据:RemoveData方法用于从缓存中移除数据。

4、用户控件缓存

控件缓存则是缓存控件的状态和视图状态,使得控件在后续请求中不需要重新初始化和加载。这在控件中包含复杂逻辑或数据库查询时非常有用。

示例代码
在控件级缓存中,通常通过重写LoadViewState和SaveViewState方法来实现状态管理,但这通常用于更复杂的情况。更简单的方法是在Page_Load事件或控件加载事件中检查缓存中是否存在数据,如果不存在,则从数据库加载数据并存入缓存。

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    LoadCachedData();
}

private void LoadCachedData()
{
    if (HttpContext.Current.Cache["ProductList"] == null)
    {
        List<Product> products = GetProductsFromDatabase();
        HttpContext.Current.Cache.Insert("ProductList", products, null, DateTime.Now.AddMinutes(30), TimeSpan.Zero);
    }
    else
    {
        List<Product> products = (List<Product>)HttpContext.Current.Cache["ProductList"];
        // Use the cached data
    }
}

在这个C#示例中,OnInit方法首先检查缓存中是否存在ProductList,如果不存在,则从数据库加载产品列表并存储到缓存中,缓存时间为30分钟。

5、使用缓存配置

如果需要为多个页面定义相同的缓存配置,可以在web.config文件中添加一个缓存配置,并将这个缓存配置应用到多个页面。使用统一的缓存配置有利于管理应用程序中多个缓存,如果要更改缓存设置,不用每页都新辛苦地重新设置。

在web.config中提供了下的配置节,开发人员可以统一配置。

<configuration>
  <system.web>
    <!-- 其他配置 -->

    <!-- 定义缓存配置 -->
    <caching>
      <outputCacheProfiles>
        <!-- 定义一个缓存配置,例如“DefaultCache” -->
        <add 
          profileName="DefaultCache"
          varyByParam="none"
          location="Any"
          duration="30"
          varyByCustom=""
          varyByHeaders=""
          varyByControls=""
          noStore="false"
          />
        
        <!-- 可以添加多个配置 -->
        <add 
          profileName="ShortCache"
          varyByParam="none"
          location="Any"
          duration="5"
          />
      </outputCacheProfiles>
    </caching>
    
    <!-- 其他配置 -->
  </system.web>

  <!-- 其他配置 -->
</configuration>

在上述配置中,“DefaultCache”是一个缓存配置,设置了默认的缓存持续时间为30分钟(duration=“30”)。而“ShortCache”则设定了更短的缓存时间,仅为5分钟,适用于需要更频繁更新的页面

6、使用HttpCachePolicy类控制缓存

使用声明性的方式配置缓存简单且实用,但是也可以通过Response类的Cache属性来控制缓存。这是一个HttpCachePolicy类型的实例,可以通过该类的属性来调整页面缓存。

下面使用Response.Cache类来设置页面缓存,并指定缓存时间为60s,代码如下:

protected void Page_Load(object sender, EventArgs e)
        {
            // 在服务器端缓存此页
            Response.Cache.SetCacheability(HttpCacheability.Public);

            // 设置缓存的超时时间
            Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));

            // 是否应忽略由使缓存无效的客户端发送的HTTP Cache-Control标头
            Response.Cache.SetValidUntilExpires(true);

            Label1.Text = "现在的时间是<br/>" + DateTime.Now.ToString();
        }

在这里插入图片描述
下面使用Response.Cache属性根据浏览器的类型来缓存页。代码如下所示:

protected void Page_Load(object sender, EventArgs e)
        {
             在服务器端缓存此页
            //Response.Cache.SetCacheability(HttpCacheability.Public);

             设置缓存的超时时间
            //Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));

             是否应忽略由使缓存无效的客户端发送的HTTP Cache-Control标头
            //Response.Cache.SetValidUntilExpires(true);

            //Label1.Text = "现在的时间是<br/>" + DateTime.Now.ToString();

            Response.Cache.SetExpires(DateTime.Now.AddMinutes(1d));
            Response.Cache.SetCacheability(HttpCacheability.Public);
            Response.Cache.SetValidUntilExpires(true);
            Response.Cache.SetVaryByCustom("browser");
        }

三、缓存数据

除了使用缓存之外,ASP.NET还有一个强大和易于使用的缓存机制,允许开发人员在程序运行时将需要大量服务器资源的对象保存到缓存中。比如从数据库获取一个DataSet对象,然后将其动态插入缓存,在后续多次使用该对象时,将从缓存中直接获取。

本节将讨论ASP.NET提供的Cache类来缓存应用程序数据,Cache类位于System.Web.Caching命名空间中。ASP.NET的Page类中有一个Cache属性用于保存页面缓存信息,可以使用该类来缓存一些应用程序数据。

使用Cache类缓存应用程序数据是最灵活的一种缓存类型,尽管需要编写代码。一个通用的原则是不要随意缓存数据,而应该只是缓存一些特别占用资源的数据,使用Cache类缓存数据具有如下特点:

  • Cache对象是线程安全的,在编写多线程应用时不需要显式地加锁或解锁对象。
  • Cache中的对象如果过期,则会自动被移除。因此在从Cache对象中获取数据时,需要先判断是否存在所要获取的对象。
  • Cache对象支持缓存依赖,可以将Cache对象与一个文件、一个数据库表或其他任何类型的资源相关联,如果发生了改变,Cache对象可以自动地被移除或更新。

1、添加缓存项

Cache对象与Application对象和Session对象类似,同样提供了键值对的形式来保存对象。可以使用如下的语法将对象添加到Cache集合中:

Cache["key"]=item;

通常建议使用Cache对象的Insert或者是Add重载方法添加对象到缓存,可以精细地控制缓存对象的各项参数,比如指定到期时间,设置缓存依赖等等。Add方法与Insert方法的一个区别是Add方法会返回添加到缓存中的对象,并且如果缓存集合中具有相同键的缓存对象,Add方法将会引发异常。

下面将演示如何在应用程序中使用Cache对象。新建一个名称为CacheObjectDemo.aspx的网页,在该页面上放一个GridVi
ew对象。

本示例将从Northwind中获取产品表信息,并保存到Cache对象中。在使用时,如果Cache对象没有相应的对象,则从数据库中获取,并调用Cache对象的Insert方法将DataSet对象插入到缓存中。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;


namespace CacheObjectDemo
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // 首先从Cache中获取DataSet
            DataSet products = (DataSet)Cache["Products"];
            // 如果Cache中不存在DataSet,则从数据库中获取DataSet,并添加到缓存中
            if (products == null)
            {
                products = GetProductDataSet();
                Cache.Insert("Products", products);
            }
            GridView1.DataSource = products;
            GridView1.DataMember = "productsTable";
            GridView1.DataBind();
        }

        /// <summary>
        /// 从数据库中获取产品信息,并返回一个DataSet对象
        /// </summary>
        /// <returns></returns>
        protected DataSet GetProductDataSet()
        {
            string connstr = WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
            DataSet ds = new DataSet();
            using (SqlConnection conn=new SqlConnection(connstr))
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand("Select * from Products", conn);
                SqlDataAdapter sda = new SqlDataAdapter(cmd);
                sda.Fill(ds, "productsTable");
            }
            return ds;
        }
    }
}

代码中使用了Insert方法向Cache对象中插入了一个缓存,Insert还有几个不同参数的重载方法。

2、指定缓存依赖

当缓存依赖向缓存中插入一个对象时,该对象的状态取决于一个外部对象,比如一个XML文件,一个SQL数据库表。每当外部对象发生更改时,缓存将自动从缓存集合中移除。
ASP.NET包括如所示的三种缓存依赖:

  • CacheDependency:允许基于文件或其他缓存键创建依赖。
  • SqlCacheDependency:基于SqlServer的表或者是一个SqlServer查询的依赖。
  • AggregateCacheDependency:基于多个缓存依赖项的依赖,比如可以同时组合SQL依赖和文件依赖。

示例代码为如何使用Insert方法为指定的缓存项添加一个缓存依赖:

 protected void Page_Load(object sender, EventArgs e)
        {
            // 首先从Cache中获取DataSet
            DataSet products = (DataSet)Cache["Products"];
            // 如果Cache中不存在DataSet,则从数据库中获取DataSet,并添加到缓存中
            if (products == null)
            {
                products = GetProductDataSet();
                CacheDependency cd = new CacheDependency(Server.MapPath("web.config"));
                // 在Insert中指定该依赖项
                Cache.Insert("Products", products, cd, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromHours(1)) ;
            }
            GridView1.DataSource = products;
            GridView1.DataMember = "productsTable";
            GridView1.DataBind();
        }

在该代码中,首先实例化了一个基于web.config文件的缓存依赖,当该文件被修改时,Cache中相应的缓存项也将被移除。

3、缓存优先级

在ASP.NET中,缓存优先级是通过CacheItemPriority枚举来设定的,它决定了缓存中的项目在内存压力下被移除的顺序。

在ASP.NET中,缓存是一个重要的性能优化手段,通过暂存数据来减少数据库访问次数和数据处理时间。不同的缓存策略对应用性能的影响也不同,因此合理设置和管理缓存优先级对于保证关键数据的可用性和提高系统整体性能至关重要。

CacheItemPriority枚举有多个可选值,用于设置缓存中项目的优先级。这些值决定了当系统内存不足时,哪些缓存项被保留,哪些被移除。具体如下:

优先级枚举说明
NotRemovable此优先级的缓存项不会被 Cache 机制自动删除,但可以通过编程手动删除。
NoPriority这是默认值,不设置优先级,让 Cache 管理器根据需要自由地删除项目。
High具有高优先级,只有在内存非常紧张时才会被删除。
AboveNormal较高优先级,通常不会删除,除非系统内存压力较大。
BelowNormal较低优先级,更有可能在其他项目之前被删除。
Low低优先级,将最先被删除以释放内存。
Default默认删除策略,类似于 NoPriority。
AboveHigh比 High 还要高的优先级,极为重要,几乎不会被删除。

总的来说,合理使用缓存优先级不仅可以提高应用性能,还能确保关键数据的可用性。在实际应用中,需要根据数据的重要性和访问频率来灵活设置缓存优先级,以达到最优的性能表现。

示例代码:

using System;
using System.Web;

public class CacheExample
{
    public void SetCacheWithPriority()
    {
        // 创建一个缓存项对象
        CacheItemPriority priority = CacheItemPriority.High; // 设置缓存优先级为高
        string cacheKey = "MyCachedData";
        string cacheValue = "This is some important data that needs to be cached.";

        // 将数据添加到缓存中,并指定优先级
        HttpContext.Current.Cache.Insert(cacheKey, cacheValue, null, DateTime.Now.AddHours(1), TimeSpan.Zero, priority);
    }

    public string GetCachedData()
    {
        string cacheKey = "MyCachedData";
        return HttpContext.Current.Cache[cacheKey] as string;
    }
}

在上面的示例中,我们首先创建了一个名为SetCacheWithPriority的方法,用于向缓存中添加一个具有高优先级的缓存项。然后,我们定义了一个名为GetCachedData的方法,用于从缓存中获取数据。

在SetCacheWithPriority方法中,我们使用CacheItemPriority.High设置了缓存项的优先级为高。这意味着这个缓存项在内存紧张时不太可能被删除。我们还使用了HttpContext.Current.Cache.Insert方法将数据添加到缓存中,并指定了缓存键、值、过期时间和优先级。

4、使用缓存删除通知

ASP.NET中的缓存删除通知是一种机制,用于在缓存项被移除时触发特定的事件或执行特定的操作。这可以帮助开发人员在缓存项失效或被移除时采取适当的措施,例如更新数据库、发送通知等。

要使用缓存删除通知,你需要创建一个实现了IDisposable接口的类,并在其中定义一个名为Dispose的方法。当缓存项被移除时,ASP.NET会自动调用这个方法。你可以在Dispose方法中编写逻辑来处理缓存项的移除事件。

下面是一个示例代码,演示了如何在ASP.NET中使用缓存删除通知:

using System;
using System.Web;

public class CacheItemRemovedNotifier : IDisposable
{
    private string cacheKey;
    private object state;

    public CacheItemRemovedNotifier(string cacheKey, object state)
    {
        this.cacheKey = cacheKey;
        this.state = state;
    }

    public void Dispose()
    {
        // 在这里处理缓存项被移除的逻辑
        Console.WriteLine($"Cache item with key '{cacheKey}' has been removed.");
        // 可以在这里执行其他操作,如更新数据库、发送通知等
    }
}

public class CacheExample
{
    public void AddCacheWithNotification(string cacheKey, object value)
    {
        // 创建一个缓存项对象
        CacheItemPriority priority = CacheItemPriority.High; // 设置缓存优先级为高
        TimeSpan expiration = TimeSpan.FromHours(1); // 设置缓存过期时间为1小时

        // 将数据添加到缓存中,并指定优先级和过期时间
        HttpContext.Current.Cache.Insert(cacheKey, value, null, DateTime.Now.Add(expiration), expiration, priority, new CacheItemRemovedCallback(OnCacheItemRemoved));
    }

    private void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason)
    {
        // 创建缓存删除通知对象
        var notifier = new CacheItemRemovedNotifier(key, value);
        // 注册缓存删除通知
        HttpContext.Current.ApplicationInstance.Lock();
        HttpContext.Current.ApplicationInstance[key] = notifier;
        HttpContext.Current.ApplicationInstance.UnLock();
    }
}

在上面的示例中,我们首先创建了一个名为CacheItemRemovedNotifier的类,它实现了IDisposable接口。然后,我们在CacheExample类中定义了一个名为AddCacheWithNotification的方法,用于向缓存中添加一个具有高优先级的缓存项,并指定了缓存键、值、过期时间和回调函数OnCacheItemRemoved。

在OnCacheItemRemoved方法中,我们创建了一个CacheItemRemovedNotifier对象,并将其注册到应用程序实例中。这样,当缓存项被移除时,ASP.NET会自动调用CacheItemRemovedNotifier对象的Dispose方法,从而触发缓存删除通知。

5、数据源控件缓存

ASP.NET中的数据源控件缓存是一种机制,用于将数据源控件(如SqlDataSource、ObjectDataSource等)的结果缓存起来,以提高性能和减少数据库访问次数。通过缓存数据源控件的结果,可以在一段时间内重复使用这些结果,而不必每次都从数据库中检索它们。
要启用数据源控件的缓存,可以使用以下属性:

数据源控件缓存相关的属性说明
CacheDuration指定缓存持续时间,以秒为单位。默认值为300秒(5分钟)。
EnableCaching设置为true以启用缓存。默认值为false。
CacheExpirationPolicy指定缓存过期策略。可选值包括Absolute(绝对时间)、Sliding(滑动时间)和None(不缓存)。
CacheKeyDependency指定缓存键依赖项,以便在相关资源更改时自动清除缓存。

下面是一个示例代码,演示如何在ASP.NET中使用SqlDataSource控件进行缓存:

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="YourConnectionString" SelectCommand="SELECT * FROM YourTable">
    <Selecting>
        <!-- 设置缓存参数 -->
        <Cache Duration="60" EnableCaching="true" CacheExpirationPolicy="Sliding" />
    </Selecting>
</asp:SqlDataSource>

在上面的示例中,我们设置了以下缓存参数:

  • Duration为60秒,表示缓存将持续60秒。
  • EnableCaching设置为true,表示启用缓存。
  • CacheExpirationPolicy设置为Sliding,表示缓存将在指定的时间段后过期,并在每次请求时重新验证。

请注意,上述示例中的连接字符串和查询语句需要根据你的实际情况进行替换。此外,还可以根据需要调整其他缓存参数以满足特定的需求。

四、缓存依赖

ASP.NET中的缓存依赖是指在缓存项与其他资源之间建立一个链接,使得当这个资源发生变化时,相关的缓存项会自动失效并被更新。这确保了应用程序所使用数据的时效性和一致性。在Web开发中,缓存是一项非常核心的技术,它能够极大地提高应用的性能和可伸缩性。

ASP.NET提供了多种缓存机制,其中包括页面输出缓存、控件缓存以及通过Cache对象实现的数据缓存。页面输出缓存允许你将整个页面的内容或部分页面的内容缓存起来,从而避免每次请求都重新执行页面处理逻辑。控件缓存则允许你针对特定的用户控件进行缓存,与页面输出缓存相似,它可以减少数据库访问次数和页面渲染时间。而数据缓存则更为灵活,它可以对任意的对象进行缓存,例如数据库查询结果、配置文件的内容等。

关于缓存依赖,这是ASP.NET缓存机制中的一个亮点。一个缓存依赖可以是基于文件的,也可以是基于另一个缓存项的。当依赖的文件或缓存项发生变化时,相关的缓存项就会自动作废。这种机制特别适用于需要实时反映底层数据变化的场景。例如,如果一个缓存项依赖于一个数据库生成的文件,那么当数据库更新并重新生成该文件时,相关的缓存项就会自动过期并要求重新生成。通过这种方式,开发者可以确保应用程序总是使用最新的数据。

在实际开发中,开发者可以通过编程方式创建缓存依赖,并将其与缓存项关联起来。例如,可以使用CacheDependency类创建一个基于文件的缓存依赖,然后将其传递给Cache.Insert方法。此外,ASP.NET还支持基于其他缓存项的依赖关系,这意味着当一个缓存项被插入、更新或删除时,可以触发与之相关的其他缓存项的过期。

综上所述,ASP.NET中的缓存依赖功能为开发者提供了一种强大的机制,以确保缓存数据的时效性。无论是基于文件的依赖还是基于其他缓存项的依赖,都能帮助开发者容易地管理缓存数据的生命周期,保证用户总是能够获得最新的数据。在使用缓存时,开发者应始终考虑如何合理地使用缓存依赖以及其他缓存策略,以便在性能优化和数据一致性之间找到平衡点。

1、文件和缓存项依赖

ASP.NET中的文件和缓存项依赖是指将一个缓存项与一个文件关联起来,当该文件发生变化时,缓存项会自动失效并更新。这样可以确保应用程序使用的数据是最新的。

下面是一个示例代码,演示如何在ASP.NET中使用文件和缓存项依赖:

using System;
using System.Web;
using System.IO;

public class CacheDependencyExample
{
    public void AddCacheItemWithFileDependency()
    {
        // 创建一个缓存项的键值对
        string cacheKey = "MyCachedData";
        string cacheValue = "This is the cached data.";

        // 创建一个缓存依赖对象,指定要监视的文件路径
        string filePath = Server.MapPath("~/App_Data/data.txt");
        CacheDependency dependency = new CacheDependency(filePath);

        // 添加缓存项,并设置依赖关系
        HttpContext.Current.Cache.Insert(cacheKey, cacheValue, dependency, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration);
    }
}

在上面的示例中,我们首先创建了一个缓存项的键值对,然后创建了一个CacheDependency对象,指定了要监视的文件路径。接下来,我们使用HttpContext.Current.Cache.Insert方法将缓存项添加到缓存中,并设置了依赖关系。这样,当指定的文件(在这个例子中是"~/App_Data/data.txt")发生变化时,缓存项就会自动失效并更新。

需要注意的是,上述示例中的文件路径使用了Server.MapPath方法来获取实际的文件路径。在实际项目中,你需要根据你的项目结构和需求来确定正确的文件路径。

2、聚合依赖

ASP.NET中的聚合依赖是指将多个缓存项关联起来,当其中一个缓存项发生变化时,所有关联的缓存项都会自动失效并更新。这样可以确保应用程序使用的数据是最新的。

下面是一个示例代码,演示如何在ASP.NET中使用聚合依赖:

using System;
using System.Web;

public class AggregateCacheDependencyExample
{
    public void AddAggregateCacheItems()
    {
        // 创建两个缓存项的键值对
        string cacheKey1 = "MyCachedData1";
        string cacheValue1 = "This is the first cached data.";
        string cacheKey2 = "MyCachedData2";
        string cacheValue2 = "This is the second cached data.";

        // 创建一个缓存依赖对象
        CacheDependency dependency = new CacheDependency(null, new string[] { cacheKey1, cacheKey2 });

        // 添加缓存项,并设置依赖关系
        HttpContext.Current.Cache.Insert(cacheKey1, cacheValue1, dependency, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration);
        HttpContext.Current.Cache.Insert(cacheKey2, cacheValue2, dependency, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration);
    }
}

在上面的示例中,我们首先创建了两个缓存项的键值对,然后创建了一个CacheDependency对象,并将这两个缓存项的键作为依赖项传递给它。接下来,我们使用HttpContext.Current.Cache.Insert方法将缓存项添加到缓存中,并设置了依赖关系。这样,当任何一个缓存项(在这个例子中是"MyCachedData1"或"MyCachedData2")发生变化时,所有关联的缓存项都会自动失效并更新。

需要注意的是,上述示例中的依赖项是通过传递一个字符串数组来指定的。在实际项目中,你需要根据你的需求来确定正确的依赖项。

3、配置SQL缓存依赖

ASP.NET中的SQL缓存依赖是一种更为高级的缓存策略,它能够将缓存项与SQL Server数据库中的查询结果关联起来。当数据库中的数据发生变化时,相关的缓存项会自动失效并更新,从而确保应用程序使用的是最新的数据。

要实现SQL缓存依赖,需要以下几个步骤:

  • 配置数据库:为了让ASP.NET能够侦测到数据库变动,需要在数据库中启用Service Broker消息传递服务,并创建一个与特定查询相关联的缓存依赖跟踪表。

  • 创建SqlCacheDependency对象:通过指定数据库连接字符串、表名和查询命令,创建一个SqlCacheDependency对象。

  • 添加带有依赖的缓存项:将创建好的SqlCacheDependency对象与缓存项一起添加到System.Web.Caching.Cache中。

下面是一个配置好数据库和支持SQL缓存依赖的示例代码:

using System;
using System.Configuration;
using System.Web;
using System.Web.Caching;
using System.Data;
using System.Data.SqlClient;

public class SqlCacheDependencyExample
{
    public void AddCacheItemWithSqlDependency()
    {
        // 从配置文件获取数据库连接字符串
        string connectionString = ConfigurationManager.ConnectionStrings["MyDbConnectionString"].ConnectionString;

        // 定义SQL查询语句
        string selectStatement = "SELECT * FROM Employees";

        // 创建SqlCacheDependency对象
        SqlCacheDependency sqlDependency = new SqlCacheDependency(connectionString, "Employees");

        // 获取数据
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            SqlCommand command = new SqlCommand(selectStatement, connection);
            connection.Open();
            SqlDataAdapter adapter = new SqlDataAdapter(command);
            DataSet ds = new DataSet();
            adapter.Fill(ds);
        }

        // 添加缓存项,并设置依赖关系
        HttpContext.Current.Cache.Insert("MyEmployees", ds, sqlDependency, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration);
    }
}

在上面的示例中,我们首先从配置文件中获取了数据库连接字符串,然后定义了一个SQL查询语句,用于从数据库中选择所有员工记录。接下来,我们创建了一个SqlCacheDependency对象,并将查询语句和数据库表名传递给它。之后,我们执行数据库查询并将结果存储在一个DataSet对象中。最后,我们将这个数据集添加到缓存中,并设置了SQL缓存依赖。

需要注意的是,上述示例假设你已经在数据库中配置了Service Broker,并且已经有一个名为"Employees"的表。在实际项目中,你需要根据你的数据库结构和需求来调整SQL查询语句和缓存依赖的配置。

4、使用SQL缓存依赖

ASP.NET中的SQL缓存依赖允许开发人员将缓存项与数据库查询结果关联起来。当数据库中的数据发生变化时,相关的缓存项会自动失效并更新,从而确保应用程序使用的是最新的数据。

下面是一个使用SQL缓存依赖的例子:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Caching;

public class CacheDependencyExample
{
    private string connectionString = "your_connection_string"; // 替换为你的数据库连接字符串

    public void AddCacheItemWithSqlDependency()
    {
        // 定义SQL查询语句
        string selectStatement = "SELECT * FROM Products";

        // 创建SqlConnection对象
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            // 打开数据库连接
            connection.Open();

            // 创建SqlCommand对象
            using (SqlCommand command = new SqlCommand(selectStatement, connection))
            {
                // 执行查询并将结果存储在DataSet对象中
                using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                {
                    DataSet dataSet = new DataSet();
                    adapter.Fill(dataSet);

                    // 创建SqlCacheDependency对象,指定表名和查询语句
                    SqlCacheDependency sqlDependency = new SqlCacheDependency(connectionString, "Products", selectStatement);

                    // 添加带有依赖的缓存项
                    HttpContext.Current.Cache.Insert("MyProducts", dataSet, sqlDependency, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration);
                }
            }
        }
    }
}

在上面的示例中,我们首先定义了一个SQL查询语句,用于从数据库中选择所有产品记录。然后,我们创建了一个SqlConnection对象,并打开了数据库连接。接下来,我们创建了一个SqlCommand对象,并执行了查询。我们将查询结果存储在一个DataSet对象中。然后,我们创建了一个SqlCacheDependency对象,并将数据库连接字符串、表名和查询语句传递给它。最后,我们将这个数据集添加到缓存中,并设置了SQL缓存依赖。

需要注意的是,上述示例假设你已经在数据库中配置了Service Broker,并且已经有一个名为"Products"的表。在实际项目中,你需要根据你的数据库结构和需求来调整SQL查询语句和缓存依赖的配置。

总结

在ASP.NET中,缓存依赖是指将缓存项与某个资源关联起来,当这个资源发生变化时,相关的缓存项会自动失效并更新。这种机制帮助开发人员确保应用程序使用的数据是最新的,从而提高应用程序的性能和可靠性。

缓存依赖主要有三种类型:文件依赖、键值依赖和SQL依赖。下面将详细介绍每种类型的缓存依赖及其对应的类和作用:

  1. 文件依赖
  • 对应类:CacheDependency 类。
  • 作用:基于特定文件的更改来使缓存项失效。当一个文件发生更改时,所有依赖于这个文件的缓存项都会失效。这种类型的依赖在静态内容较多的应用场景中非常有用,例如网站中的一些不常变的静态资源(如js、css文件)可以通过文件依赖进行缓存,一旦文件被更新,相关的缓存即会失效并重新加载新的文件内容。
  1. 键值依赖
  • 对应类:CacheDependency 类。
  • 作用:缓存项依赖于另一个缓存项的键值。当这个键值发生变化时,相关的缓存项将会失效并更新。这种方式适用于需要多级缓存依赖的场景,例如在一个电商平台中,商品的价格可能依赖于其库存量的缓存项,当库存量发生变化时,价格缓存项可以自动失效并更新。
  1. SQL依赖
  • 对应类:SqlCacheDependency 类。
  • 作用:最复杂的一种,基于SQL Server并允许缓存项依赖于数据库中的查询结果。当数据库中的数据发生更改时,相关联的缓存项将自动失效并更新。这种依赖机制非常适用于动态网站和应用程序,这些网站和应用程序需要实时反映数据库状态的变化。例如,一个在线订票系统可以使用SQL依赖来缓存查询结果(如车次信息和座位可用性),保证用户始终看到的是最新状态。

综上所述,理解这些缓存依赖的工作方式和适用场景,可以帮助开发者更有效地利用ASP.NET的缓存机制,从而提升应用性能和用户体验。在选择适合的缓存依赖类型时,开发者应根据具体的应用需求和数据变动频率来做决策。

<think>好的,用户遇到了Git合并时本地更改会被覆盖的问题,需要解决方案。根据之前的引用资料,解决方法主要有commit、stash和revert三种。首先,我得确认用户的具体情况,比如他们的本地更改是否已经完成,是否需要保留,或者是否可以丢弃。用户可能不太清楚这三种方法的适用场景,需要详细解释每个选项的步骤和优缺点。比如,commit适用于需要保留更改的情况,stash适合临时保存以便后续恢复,而revert则是直接撤销更改,适用于不需要保留的情况。需要结构清晰,分点说明,每个方法都给出操作步骤和适用场景,帮助用户理解哪种情况最适合他们。还要注意使用中文,避免技术术语过于复杂,让用户容易理解。同时,生成相关问题,可能涉及如何恢复stash的内容,或者如何避免频繁冲突等,扩展用户的知识点。另外,要确保LaTeX格式正确,但在这个问题中可能用不上数学公式,所以主要关注代码块和引用标识。检查引用是否正确,比如引用[^1]和[^2]的来源是否相关,用户提供的引用内容是否准确对应解决方案。 最后,确保回答真实可靠,操作步骤准确无误,避免误导用户。可能还需要提醒用户根据具体情况选择方法,比如如果有未完成的实验性代码,stash可能是更好的选择,而如果是确定要保留的修改,则应该commit。</think>要解决Git合并时本地更改被覆盖的问题,可根据不同场景选择以下三种方法: ### 一、提交本地更改(commit) **适用场景**:当本地更改已测试通过且需要保留到版本历史中。 **操作步骤**: 1. 将改动添加到暂存区: ```bash git add . # 添加所有文件 # 或指定文件 git add file1.txt file2.py ``` 2. 提交更改并添加描述: ```bash git commit -m "完成用户登录模块优化" ``` 3. 执行合并操作: ```bash git merge origin/main ``` **优点**:保留完整的开发记录,便于后续追溯[^1]。 ### 二、暂存更改(stash) **适用场景**:需要临时保存未完成的修改(如调试代码),优先处理合并操作。 **操作步骤**: 1. 保存当前工作状态: ```bash git stash # 可选添加备注 git stash save "用户登录模块调试代码" ``` 2. 查看暂存记录列表: ```bash git stash list ``` 3. 合并远程分支: ```bash git merge origin/main ``` 4. 恢复暂存内容: ```bash git stash pop # 恢复并删除最近一次暂存 # 或指定特定暂存 git stash apply stash@{1} ``` **优点**:保持工作目录整洁,特别适合处理紧急合并任务[^2]。 ### 三、撤销本地更改(revert) **适用场景**:本地修改可丢弃(如实验性代码或错误修改)。 **操作步骤**: 1. 撤销所有未提交的修改: ```bash git checkout -- . # 部文件 # 或指定文件 git checkout -- file1.txt ``` 2. 执行合并操作: ```bash git merge origin/main ``` **风险提示**:此操作不可逆,需确认文件无需保留。 --- ### 对比决策表 | 方法 | 保留记录 | 可恢复性 | 适用阶段 | |---------|----------|----------|------------------| | commit | ✅ | ✅ | 功能开发完成时 | | stash | ❌ | ✅ | 开发中途临时切换 | | revert | ❌ | ❌ | 放弃无效修改 | ### 扩展应用场景 - 当存在多个暂存时,可用`git stash list`查看记录,通过`git stash apply stash@{n}`精准恢复 - 合并后出现冲突时,可使用`git mergetool`可视化工具解决冲突 - 长期分支开发推荐使用`git rebase`保持提交历史线性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值