65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 缓存面试题:第二部分

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.25/5 (23投票s)

2008年8月22日

CPOL

7分钟阅读

viewsIcon

72123

ASP.NET 缓存面试题 第二部分

缓存概念

引言

在本节中,我们将重点介绍缓存,这是 ASP.NET 面试中最常被问到的问题之一。我还创建了一个包含 25 个 ASP.NET 面试问题的视频系列,请务必观看以了解更多关于面试中提问的问题类型。

我之前发布的架构师面试题系列的前几部分

UML 面试题 第一部分: SoftArch5.aspx

祝您求职愉快......

(I) 在 ASP.NET 2.0 中,我们如何启用 SQL 缓存依赖关系?

以下是启用 SQL 缓存依赖关系的广泛步骤:

aspnet_regsql -ed -E -d Northwind
  • 启用数据库的通知。
  • 启用单个表的通知。
  • 使用 web.config 文件启用 ASP.NET 轮询。
  • 最后,在您的 ASP.NET 代码中使用缓存依赖关系对象。
  • 启用数据库的通知。
  • 在使用 SQL Server 缓存失效之前,您需要为数据库启用通知。此任务使用 aspnet_regsql.exe 命令行实用程序执行,该实用程序位于 c:\[WinDir]\Microsoft.NET\Framework\[Version] 目录中。
    • -ed:命令行开关
    • -E:使用受信任的连接
    • -S:指定服务器名称,如果是当前计算机以外的计算机
    • -d:数据库名称

现在让我们尝试了解 aspnet_regsql.exe 在数据库中做了什么。执行 aspnet_regsql -ed -E -d Northwind 命令后,您将看到一个新表和四个新存储过程被创建。

图 5.1 - 为通知创建的 SQL 缓存表

本质上,当发生更改时,会在此表中写入一条记录。SQL Server 轮询查询此表以查找更改。

图 5.2:新创建的存储过程

简单介绍一下这些存储过程的作用:

  • AspNet_SqlCacheRegisterTableStoredProcedure:此存储过程将一个表设置为支持通知。此过程通过向表添加一个通知触发器来实现,该触发器在插入、删除或更新任何行时触发。
  • AspNet_SqlCacheUnRegisterTableStoredProcedure:此存储过程接受一个已注册的表并删除通知触发器,以便不会生成通知。
  • AspNet_SqlCacheUpdateChangeIdStoredProcedure:通知触发器调用此存储过程来更新 AspNet_SqlCacheTablesForChangeNotification 表,从而指示该表已更改。
  • Asp Net_SqlCacheQueryRegisteredTablesStoredProcedure:它仅从 AspNet_SqlCacheTablesForChangeNotification 表中提取表名。它用于快速查看所有已注册的表。
  • AspNet_SqlCachePollingStoredProcedure:这将从 AspNet_SqlCacheTablesForChangeNotification 表中获取更改列表。它用于执行轮询。

为单个表启用通知

一旦创建了必要的存储过程和表,我们就必须通知哪些表需要启用通知。这可以通过两种方式实现:

  • aspnet_regsql -et -E -d Northwind -t Products
  • Exec spNet_SqlCacheRegisterTableStoredProcedure 'TableName'

为通知注册表会在表中创建触发器。例如,对于“Products”表,会创建以下触发器。因此,对“Products”表的任何修改都将更新 AspNet_SqlCacheNotification 表。

CREATE TRIGGER

dbo.[Products_AspNet_SqlCacheNotification_Trigger] ON
[Products] 
FOR INSERT, UPDATE, DELETE
AS 
BEGIN
SET NOCOUNT ON
EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure
N'Products‘
END

AspNet_SqlCacheTablesForChangeNotification 包含您正在监视的每个表的单个记录。当您在表中进行更改(例如插入、删除或更新记录)时,change Id 列将增加 1。ASP.NET 会反复查询此表以跟踪每个表的最新更改值。当此值在后续读取中发生更改时,ASP.NET 就知道该表已更改。

图 5.3:缓存通知表中的条目

使用 web.config 文件启用 ASP.NET 轮询。现在我们的数据库端都已配置好,为了在 ASP.NET 端实现 SQL 缓存,我们需要在 web.config 文件中进行一些配置。我们需要在 web.config 文件中设置两个属性:

  • Enabled 属性设置为 true 以启用缓存。
  • 将 poll time 属性设置为每次轮询之间的时间(以毫秒为单位)。

下面是 web.config 文件的快照。

图 5.4:用于 SQL 缓存的 Web.config 文件修改

最后,在您的 ASP.NET 代码中使用缓存依赖关系对象。现在是最后一步,将我们的缓存依赖关系与编程数据缓存、数据源控件和输出缓存结合使用。对于编程数据缓存,我们需要创建一个新的 SqlCacheDependency 并将其提供给 Cache.Insert() 方法。在 SqlCacheDependency 构造函数中,您提供两个字符串。第一个是在 web.config 文件中的 <...> 部分定义的数据库名称,例如:Northwind。第二个是链接表的名称,例如:Products。

private static void CacheProductsList(List<ClsProductItem> products)
{
    SqlCacheDependency sqlDependency = new SqlCacheDependency("Northwind", "Products");
    HttpContext.Current.Cache.Insert("ProductsList", products, sqlDependency, 
                DateTime.Now.AddDays(1), Cache.NoSlidingExpiration);
}
private static List<ClsProductItem> GetCachedProductList()
{
    return HttpContext.Current.Cache["ProductsList"] as List<ClsProductItem>;
}

ClsProductItem 是业务类,这里我们尝试缓存 ClsProductItem 的列表,而不是 DataSet 或 DataTable。以下方法由 ObjectDataSource 控件用于检索 ProductList

public static List<ClsProductItem> GetProductsList(int catId, string sortBy)
{
    //Try to Get Products List from the Cache
    List<ClsProductItem> products = GetCachedProductList();
    if (products == null)
    {
        //Products List not in the cache, so query the Database layer
        ClsProductsDB db = new ClsProductsDB(_connectionString);
        DbDataReader reader = null;
        products = new List<ClsProductItem>(80);
        if (catId > 0)
        {
            //Return Product List from the Data Layer
            reader = db.GetProductsList(catId);
        }
        else
        {
            //Return Product List from the Data Layer
            reader = db.GetProductsList();
        }
        //Create List of Products -List if ClsProductItem-
        products = BuildProductsList(reader);
        reader.Close();

        //Add entry to products list in the Cache
        CacheProductsList(products);
    }
    products.Sort(new ClsProductItemComparer(sortBy));

    if (sortBy.Contains("DESC")) products.Reverse();
    return products;
}

要使用输出缓存执行相同的技巧,您只需将 SqlDependency 属性设置为数据库依赖关系名称和表名,用冒号分隔。

<%@ OutputCache Duration="600" SqlDependency="Northwind:Products" VaryByParam="none" %>

相同的技术也适用于 SqlDataSourceObjectDataSource 控件。

<asp:SqlDataSource EnableCaching="True" SqlCacheDependency="Northwind:Products" ... />

注意ObjectDataSource 不支持为自定义类型(如我们示例中的类型)内置缓存。它仅对此功能支持 DataSet 和 DataTable。

为了进行抽样检查,请运行 SQL Server Profiler,看看第一次运行后 SQL 是否真的命中数据库。

(I) 什么是缓存后替换?

当我们需要缓存整个页面但又需要在该缓存页面中包含一些动态区域时,可以使用缓存后替换。例如,QuoteoftheDay(每日名言)、RandomPhotos(随机照片)和 AdRotator(广告轮播)等是我们可以实现缓存后替换的示例。缓存后替换可以通过两种方式实现:

  • 调用新的 Response.WriteSubstitution 方法,并将所需的替换方法回调的引用传递给它。
  • 在页面上所需位置添加一个 <asp:Substitution> 控件,并将其 methodName 属性设置为回调方法的名称。

图 5.5:“Writesubstitution”应用示例

您可以看到我们有一个静态函数 GetDateToString()。我们将响应替换回调传递给 WriteSubstitution 方法。因此,当 ASP.NET 页面框架检索缓存的页面时,它会自动触发您的回调方法以获取动态内容。然后,它会将您的内容插入到页面的缓存 HTML 中。即使您的页面尚未缓存(例如,它是第一次渲染),ASP.NET 仍会以相同的方式调用您的回调以获取动态内容。因此,您创建一个生成一些动态内容的方法,通过这样做,您可以确保您的方法始终被调用,并且其内容永远不会被缓存。

上面的示例是通过使用 WriteSubstitution 实现的。现在,让我们看看如何通过使用 <asp:substitution> 控件来实现。您可以从编辑器工具箱中获取 <asp:substitution> 控件。

图 5.6:Substitution 控件

图 5.7:Substitution 应用示例

下面是一个展示替换控件如何工作的示例代码。左侧是后台代码,右侧是 ASPX 代码。我们需要在替换控件的 methodname 属性中提供方法名。

(I) 为什么 Post Cache 替换需要方法是静态的?

即使您的页面类实例不存在,ASP.NET 也应该能够调用此方法。当您的页面从缓存中提供时,页面对象不会被创建。因此,当页面来自缓存时,ASP.NET 会跳过页面生命周期,这意味着它不会创建任何控件对象或引发任何控件事件。如果您的动态内容依赖于其他控件的值,您将需要使用不同的技术,因为这些控件对象将无法用于您的回调。

如需进一步阅读,请观看以下面试准备视频和分步视频系列。

© . All rights reserved.