《解剖PetShop》之四:PetShop之ASP.NET缓存

网络安全 2025-04-05 21:21www.168986.cn网络安全知识

PetShop 4.0中的ASP.NET缓存机制:提升网站性能的关键策略

在微型计算机的世界里,Cache这个名字已经成为了一个耳熟能详的词汇。在硬件系统中,如CPU和主板芯片,都引入了高速缓冲存储器(Cache)技术,以解决CPU与内存之间的速度不匹配问题。现在,在软件设计领域,尤其是数据库驱动的Web应用程序中,缓存的利用变得尤为重要。PetShop 4.0作为一个典型的Web应用,通过采用ASP.NET缓存机制,极大地提升了网站的性能。

在.Net框架下开发的Web应用程序中,ASP.NET充分考虑了缓存机制的应用。为了快速获取数据并减少响应时间,ASP.NET提供了应用程序缓存和页输出缓存两种基本的缓存机制。

应用程序缓存允许开发者将程序生成的数据或报表业务对象放入缓存中。这些数据以键/值对的方式存储,便于根据key值快速访问数据项。这些数据项的生命周期受到限制,当数据项无效、过期或内存不足时会被移除。开发者可以通过CacheItemRemovedCallback委托定义回调方法,以在数据项被移除时收到通知。在.Net Framework中,应用程序缓存通过System.Web.Caching.Cache类实现。我们可以使用Add或Insert方法将数据项添加到应用程序缓存中。

除了应用程序缓存,页输出缓存的应用更为广泛。通过内存将处理后的ASP.NET页面存储起来,当客户端再次访问该页面时,可以省去页面处理的过程,从而提高页面访问的性能和Web服务器的吞吐量。例如在一个电子商务网站中,用户经常需要查询商品信息,这个过程涉及到数据库访问和搜索条件的匹配。利用页输出缓存可以存储第一次搜索得到的查询结果页,当用户再次查询时,就可以省去数据查询的过程,减少页面的响应时间。

页输出缓存分为整页缓存和部分页缓存。我们可以通过@OutputCache指令完成Web页面的输出缓存设置。这个指令包含Duration和VaryByParam两个参数。Duration参数用于设置页面或控件进行缓存的时间,单位为秒。通过这种方式,我们可以控制缓存的持续时间,以及根据不同的参数变化来更新缓存内容。

缓存机制在Web应用中扮演着至关重要的角色,它可以显著提高性能并优化用户体验。在ASP.NET中,OutputCache指令为我们提供了一种方便的方式来管理和优化页面或控件的缓存。

当Duration设置为60秒时,意味着缓存的有效期为60秒。在这段时间内,当用户访问相同页面或控件时,服务器将直接从缓存中提供内容,而不是重新生成页面或查询数据库,这无疑大大提高了性能和响应速度。

VaryByParam参数则允许我们根据特定参数来区分不同的缓存项。例如,在一个显示城市天气预报的页面中,我们可以根据城市名称(假设存储在名为txtCity的TextBox控件中)来缓存不同的天气信息。这样,只有当输入的城市名称与缓存中的城市匹配时,才会从缓存中获取数据,避免了因城市不同而导致的数据错误。

尽管缓存机制在提升性能方面表现出色,但它也存在一个明显的缺点:数据过期。当应用程序的数据或页面结果值发生变化时,如果在缓存有效期范围内,用户获得的可能就是过时的、不准确的数据。这种情况在数据更新频繁的系统中尤为明显,如股票系统。过时的数据可能导致决策失误,甚至造成巨大损失。

在.Net Framework 2.0中,微软引入了一种新的缓存机制,特别是SqlCacheDependency特性,解决了数据过期的问题。这一特性能够监视SQL Server数据库表中的数据变化,并在数据发生变化时自动使具有依赖性的缓存项失效,从而确保缓存中的数据始终是的。

SqlCacheDependency特性通过System.Web.Caching.SqlCacheDependency类实现。在SQL Server 2005上,这一特性得到了完全的支持。但对于较早的SQL Server版本(如7.0和2000),则需要采用轮询机制来跟踪数据变化。

为了在这些版本的SQL Server上实现SqlCacheDependency特性的支持,需要进行一些额外的配置。可以使用asp_regsql命令行工具或SqlCacheDependencyAdmin类来完成这些配置。

asp_regsql工具位于特定版本的Framework文件夹内,通过命令行方式执行该工具可以完成SQL Server的配置工作。配置完成后,SqlCacheDependency就可以正常工作,确保缓存中的数据始终是的,避免了数据过期带来的问题。

缓存机制是提升Web应用性能的重要手段,而SqlCacheDependency特性则解决了数据过期的问题,使得缓存机制更加完善和可靠。在开发和优化Web应用时,合理利用这些特性可以显著提升性能和用户体验。以PetShop 4.0为例,数据库名为MSPetShop4,使用asp_regsql工具进行配置时,命令如下:

asp_regsql -S localhost -E -d MSPetShop4 -ed

此工具具有一系列命令参数,各有其独特的功能。

使用“-?”可以显示工具的帮助功能,指导你如何使用此工具。

“-S”参数后接的是数据库服务器的名称或IP地址,这里为localhost,表示在本地机器上进行操作。

“-E”参数用于在采用windows集成验证时使用。

“-d”参数指定对哪一个数据库启用SqlCacheDependency功能,此处为MSPetShop4。

接下来,我们来看如何使用该工具对特定的数据表进行操作。例如,如果你希望对MSPetShop4数据库中的Item、Product和Category数据表启用SqlCacheDependency功能,可以执行如下命令:

asp_regsql -S localhost -E -d MSPetShop4 -t Item -et

asp_regsql -S localhost -E -d MSPetShop4 -t Product -et

asp_regsql -S localhost -E -d MSPetShop4 -t Category -et

执行上述命令后,asp_regsql工具会在MSPetShop4数据库中创建一个新的数据表AspNet_SqlCacheTablesForChangeNotification。这个表用于记录哪些数据表正在被追踪,以及它们数据变化的情况。如表中的tableName字段记录要追踪的数据表的名称,notificationCreated字段记录追踪的开始时间,changeId字段则记录数据表数据发生变化的次数。这样一来,你就可以直观地看到哪些数据表正在被监控,以及它们的变化情况。

除此之外,执行启用SqlCacheDependency功能的命令还会为数据库添加一系列存储过程,这些存储过程主要用于查询追踪的数据表的情况。还会为使用了SqlCacheDependency的表添加触发器。这些触发器会在数据表发生Insert、Update或Delete等操作时被激活。

在 ASP.NET Web 应用中,数据缓存机制的运作对于用户体验和网站性能至关重要。其中,修改 `AspNet_SqlCacheTablesForChangeNotification` 数据表的 `changeId` 字段值是缓存更新的重要环节之一。为了实现这一过程,我们创建了一个存储过程 `dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure`。此存储过程接收一个参数 `@tableName`,用于指定需要更新 `changeId` 的数据表名称。存储过程的工作机制是对指定数据表进行行级锁定(ROWLOCK),然后将 `changeId` 字段值加一,以标识数据的更新状态。

除了数据库层面的操作外,我们还可以利用编程的方式来管理数据库中的 SqlCacheDependency 特性。SqlCacheDependencyAdmin 类为我们提供了这一功能。这个类包含五个关键方法,它们在数据库缓存依赖的配置和管理中发挥着重要作用。它们分别是:DisableNotifications 和 EnableNotifications,用于为特定数据库启用或禁用 SqlCacheDependency 的更改通知;DisableTableForNotifications 和 EnableTableForNotifications,用于为数据库中的特定表启用或禁用更改通知;以及 GetTablesEnabledForNotifications,用于获取启用了 SqlCacheDependency 更改通知的所有表的列表。这些方法为开发者提供了灵活的管理工具,使他们能够根据需求动态地调整缓存依赖设置。

在实际应用中,假设我们有一个名为 `MSPetShop4` 的数据库连接字符串,我们可以使用 SqlCacheDependencyAdmin 类的方法来启用或禁用数据库的更改通知。例如,在网页加载时启用整个数据库的更改通知,或者在特定数据表(如 Product 表)上启用通知。值得注意的是,调用这些方法需要数据库账户的适当权限,包括创建表和存储过程的权限,以及在特定表上创建 SQL Server 触发器的权限。这意味着在执行这些操作时,我们需要确保有足够的权限来完成这些任务。虽然编程方式提供了更大的灵活性,但也有一些工具如 asp_regsql 可以更简单地配置和管理 SqlCacheDependency。在 PetShop 4.0 中,就采用了这样的工具,通过批处理文件来调用 asp_regsql 工具进行 SQL Server 的配置。

在 PetShop 4.0 这个 B2C 宠物网上商店的应用中,缓存机制的合理实现对于提升用户体验和网站性能至关重要。由于网站需要处理大量的数据请求和访问量,如果服务器响应不及时或页面加载缓慢,可能会导致用户流失。在体系架构设计中必须充分考虑性能问题。在追求性能的我们也不能忽视数据的准确性。只有在确保数据正确性的基础上,才能实现高效的缓存机制,为用户提供流畅、愉快的购物体验。在PetShop 3.0版本及其之前的版本中,缓存管理存在明显的局限性,尤其是在处理ASP.NET缓存时。PetShop 4.0版本带来了重大改进,特别是引入了SqlCacheDependency特性,显著提升了系统对缓存的处理能力。

针对Category、Product和Item数据表,PetShop 4.0运用了SQL Cache Invalidation技术,这是一种强大的机制。当这些数据表中的数据发生变动时,该技术能够迅速将相关的缓存项清除,确保数据的实时性和准确性。这一技术的核心在于SqlCacheDependency类,它是CacheDependency类的继承者。

为了确保系统的可扩展性,PetShop 4.0允许开发者创建自定义的CacheDependency类。为了支持这种灵活性,我们需要为CacheDependency建立一个抽象接口,并在web.config文件中进行相应的配置。

在PetShop 4.0的命名空间PetShop.ICacheDependency中,定义了一个简洁而强大的接口——IPetShopCacheDependency。这个接口只包含一个方法:

```csharp

public interface IPetShopCacheDependency

{

AggregateCacheDependency GetDependency();

}

```

AggregateCacheDependency是.Net Framework 2.0中的新星,它负责监控一组依赖项对象。只要这组对象中的任何一个发生变化,与之关联的缓存项就会被自动清除。

AggregateCacheDependency类的强大之处在于它的组合能力。它可以关联多个CacheDependency对象,甚至可以关联不同类型的CacheDependency对象。在PetShop中,我们需要为Category、Product和Item数据表建立依赖项。IPetShopCacheDependency接口的GetDependency方法,它的主要任务就是返回一个已经建立了这些依赖项的AggregateCacheDependency对象。这样,当数据表中的数据发生变化时,相关的缓存数据将自动更新,确保用户始终获得、最准确的信息。CacheDependency的实现与工厂模式的应用

在PetShop系统中,CacheDependency机制为数据的缓存提供了实时更新的能力。这一机制的核心在于为Category、Product和Item等关键数据表创建SqlCacheDependency依赖项。以下是具体的实现过程。

我们抽象出一个通用的依赖处理类TableDependency,该类实现了IPetShopCacheDependency接口。在这个类中,我们定义了如何根据web.config中的配置信息为数据库表创建SqlCacheDependency对象。配置信息如数据库名称和需要监控的表名,都通过配置管理器的AppSetting获取。这些配置信息被后,为每个数据表创建一个SqlCacheDependency对象,并添加到AggregateCacheDependency对象中。

代码示例如下:

```csharp

public abstract class TableDependency : IPetShopCacheDependency

{

protected char[] configurationSeparator = new char[] { ',' };

protected AggregateCacheDependency dependency = new AggregateCacheDependency();

protected TableDependency(string configKey)

{

string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];

string tableConfig = ConfigurationManager.AppSettings[configKey];

string[] tables = tableConfig.Split(configurationSeparator);

foreach (string tableName in tables)

dependency.Add(new SqlCacheDependency(dbName, tableName));

}

public AggregateCacheDependency GetDependency()

{

return dependency;

}

}

```

在web.config中的配置如下:

```xml

```

根据数据表间的依赖关系,不同的数据表有不同的依赖项。例如,Product数据表可能依赖于Category数据表的更新。这种依赖关系在配置文件中已经明确定义。当我们需要创建一个新的依赖项时,只需在配置文件中添加相应的配置项即可。由于TableDependency类的存在,我们可以通过继承TableDependency类来快速创建新的依赖项,如Product类就是TableDependency的一个子类。这样,我们就可以通过工厂模式来创建这些对象,提高代码的复用性和可维护性。例如:

当系统需要创建一个新的Product对象时,只需要调用相应的工厂方法即可,无需关心具体的创建过程。这就是工厂模式在CacheDependency创建中的应用。通过这种方式,我们可以更灵活地管理CacheDependency,提高系统的性能和响应速度。由于所有的依赖项都是基于接口实现的,因此我们可以方便地替换或扩展CacheDependency的实现,以适应不同的业务需求。CacheDependency的实现和工厂模式的应用是相互促进的,它们共同为PetShop系统提供了高效、灵活的数据缓存机制。在PetShop 4.0架构中,工厂模式的实现依然采用了配置文件和反射技术。位于PetShop.CacheDependencyFactory命名空间的DependencyAess类,作为创建IPetShopCacheDependency对象的工厂类,承担着重要的角色。

DependencyAess类具有三个静态方法:CreateCategoryDependency、CreateProductDependency和CreateItemDependency,它们分别用于创建不同类型的缓存依赖项。这些方法的实现都依赖于一个私有的LoadInstance方法,该方法根据配置文件中指定的类路径和类名,动态加载并创建IPetShopCacheDependency的实例。

整个工厂模式的实现过程,如图4-3所示,虽然看似简单,却蕴含了深厚的设计理念。DependencyAess类的职责是创建实现了IPetShopCacheDependency接口的类实例,如Category、Product和Item等。而这些接口的引入,主要是为了实现AggregateCacheDependency类型的对象获取。

在实际应用中,我们可以调用对象的接口方法GetDependency()来获取依赖项。为了更好地服务调用者,我们考虑对DependencyAess类进行改进,使其能直接创建AggregateCacheDependency类型对象。这样的改进虽然方便了调用者,却可能打乱DependencyAess类原有的职责划分,同时仍有可能被调用者直接调用创建IPetShopCacheDependency接口对象的行为。保留原有的DependencyAess类仍然是有必要的。

为了更好地服务调用者,PetShop 4.0的设计中引入了Facade模式。Facade模式可以将复杂的逻辑进行包装,提供一个统一的门面,将内部的子系统封装起来,统一为一个高层次的接口。这样,调用者就可以直接调用这个高层次的接口,而无需关心内部的实现细节。在图4-4中,展示了Facade模式的基本结构。

在PetShop 4.0中,通过引入Facade模式,我们可以提供更加简洁、直观的接口给调用者,让他们能够更方便地获取AggregateCacheDependency类型对象。这样,不仅简化了调用者的操作,还提高了系统的整体可维护性和可扩展性。在PetShop.Web项目中,Cache依赖项的管理对于应用程序的性能和响应速度至关重要。为了满足调用者的需求,简化获取AggregateCacheDependency对象的操作,我们引入了DependencyFacade类。

DependencyFacade类作为一道优雅的界面,封装了与AggregateCacheDependency对象相关的逻辑操作。这个类不仅让调用者可以通过简单的方法调用获取所需的依赖项,还巧妙地处理了配置信息的判断。

想象一下,当您需要使用缓存依赖项时,只需通过DependencyFacade类轻松调用相应的方法,即可获得创建相关依赖项的AggregateCacheDependency对象。这样的设计极大地简化了工作流程,提高了代码的可读性和可维护性。

在DependencyFacade类中,我们通过读取应用程序的配置信息来确定CacheDependencyAssembly的路径。这个路径可能涉及到一些复杂的逻辑或资源定位,但在DependencyFacade类中,我们为调用者提供了一个统一的接口,隐藏了这些复杂性。

具体实现上,我们提供了三个静态方法:GetCategoryDependency、GetProductDependency和GetItemDependency。这些方法首先会检查CacheDependencyAssembly的配置值是否存在且有效。如果存在,则通过DependencyAess类创建相应的依赖项并获取依赖;如果不存在或为空,则返回null对象。

在PetShop.Web项目的App_Code文件夹下,WebUtility类的GetCategoryName()和GetProductName()方法已经聪明地采用了DependencyFacade类的设计。它们通过调用DependencyFacade类的方法,轻松获取到所需的缓存依赖项,从而简化了代码逻辑,提高了应用程序的响应速度。

DependencyFacade类为我们提供了一个方便、高效的途径来管理Cache依赖项。它不仅简化了操作,还提高了应用程序的灵活性和可配置性。在PetShop.Web项目中,它的应用将带来更好的用户体验和更高的性能表现。GetCategoryName方法简介

GetCategoryName方法是一个获取类别名称的功能。它首先会检查缓存中是否已存在该类别名称的数据项。若存在,则直接通过缓存获取数据,以提高效率;若不存在,则通过业务逻辑层访问数据库,获取相应的类别名称,并将此数据存入缓存,以便后续使用。

WebUtility静态类中的GetCategoryName方法被表示层的多个页面所调用,例如Product页面。在Product页面的Page_Load事件方法中,会调用此方法获取类别名称并设置为页面的标题。若未使用缓存机制,当类别数据较多时,页面的加载会显得较为缓慢。

为了改善系统性能,我们引入了Proxy模式。在业务逻辑层BLL中,与Product、Category、Item相关的业务方法,其原始实现是调用数据访问层对象访问数据库以获取数据。而在引入缓存机制后,我们需要为这些业务方法增加缓存逻辑。这时,我们引入了代理对象,对于调用者来说,他们仍然调用的是BLL业务对象,但实际上,背后是代理对象在控制。代理对象会首先检查缓存中是否有需要的数据,若有则直接返回,否则才会去数据库中获取并更新缓存。这样,系统的性能得到了显著的提升。

PetShop.BLL.Product业务对象被赋予了新的生命力,通过为其建立代理对象ProductDataProxy,缓存机制的巧妙引入让数据获取更加高效。

这个代理对象像是数据的守护者,拥有从缓存中获取产品信息的特殊能力。当调用GetProductByCategory()方法时,它首先会检查缓存中是否已有相关数据。如果数据已经躺在温馨的缓存里,那就无需劳烦业务逻辑层去获取,直接取出即可。

若缓存中无相关数据,代理对象便会启动与业务逻辑层Product对象的沟通渠道,调用GetProductsByCategory()方法去获取数据。获取之后,这些数据并不会放任自流,而是与AggregateCacheDependency对象一起被小心翼翼地存放在缓存中,以确保下次能快速被检索到。

Proxy模式的运用在此展现了其独特的魅力,它如同一个数据缓存的桥梁,增强了我们对业务对象的控制。对于调用方来说,与真实对象的交互几乎无异,因为展现在外的接口是一致的。

从职责分离与分层设计的视角来看,这些Proxy对象应该被放置在业务逻辑层,而非表示层UI中。若追求程序的可扩展与可替换性,我们可以为真实对象与代理对象构建一个统一的接口或抽象类。但对于PetShop的特定设计而言,静态类与静态方法的方式在表示层调用中显得更为直接明了。但无论如何设计,我们都应警惕“过度设计”,避免走入复杂的迷宫。

若要赋予UI层缓存机制,让应用程序数据在缓存中自由驰骋,那么这些代理对象就可以被华丽地调用。以ProductsControl用户控件为例,只需一行简洁的代码:

productsList.DataSource = ProductDataProxy.GetProductsByCategory(categoryKey);

productsList是自定义的CustomList类型,它的DataSource属性欣然接受IList集合对象。但在PetShop 4.0的设计理念中,对于类似ProductsControl的控件,采用的是页输出缓存机制,将页面输出暂时保存在缓存中,以便快速响应用户请求。这种设计无疑提升了用户体验和应用程序的性能。从ProductsControl.ascx页面的源代码洞察PetShop的缓存策略

在富有特色的PetShop系统中,ProductsControl.ascx页面是一个关键组成部分,其源代码为我们揭示了PetShop在缓存策略上的巧妙运用。当我们浏览此页面的代码时,可以感受到ASP.NET 2.0为开发者带来的全新缓存体验。

与早期的ASP.NET 1.x版本不同,ASP.NET 2.0为用户控件引入了全新的CachePolicy属性。这一属性属于ControlCachePolicy类,允许开发者以编程方式设置ASP.NET用户控件的输出缓存。这一创新功能使得缓存策略更加灵活和高效。

在ProductsControl用户控件中,我们可以看到一个典型的CachePolicy应用示例。在Page_Load事件中,通过设置CachePolicy的Dependency属性,我们可以关联与该用户控件相关的依赖项。例如:

```csharp

protected void Page_Load(object sender, EventArgs e)

{

this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();

}

```

通过这种方式,业务数据和整个页面都可以被放入缓存中。相较于应用程序缓存,这种输出缓存设置方式在性能上有了显著提升。更令人欣喜的是,通过引入SqlCacheDependency特性,有效地避免了数据过期的尴尬情况。这一特性在PetShop 4.0中得到了广泛应用。

与此相对的是,原先为Product、Category、Item业务对象所建立的代理对象,虽然在一定程度上作为设计方法的展示被保留在系统中,但在新的缓存策略下,它们似乎被“投闲散置”。这种变化不仅优化了系统性能,还提升了用户体验。

狼蚁SEO在此为大家展示了PetShop中ASP.NET缓存的精髓所在。希望这些内容能为大家提供一个参考,同时也希望大家能够支持狼蚁SEO,共同更多关于ASP.NET缓存的奥秘。在浏览源代码的我们不禁感叹技术的不断进步,以及这些进步如何助力我们构建更优秀的Web应用。

上一篇:PHP 9 大缓存技术总结 下一篇:没有了

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by