惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
A
About on SuperTechFans
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Blog — PlanetScale
Blog — PlanetScale
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
G
Google Developers Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
Cloudbric
Cloudbric
L
LINUX DO - 最新话题
MyScale Blog
MyScale Blog
H
Heimdal Security Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
S
Security @ Cisco Blogs
Latest news
Latest news
I
Intezer
L
Lohrmann on Cybersecurity
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Threatpost
博客园 - 【当耐特】
S
Schneier on Security
P
Privacy International News Feed
G
GRAHAM CLULEY
T
Tenable Blog
AWS News Blog
AWS News Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
博客园 - Franky
Engineering at Meta
Engineering at Meta
美团技术团队
S
Secure Thoughts
T
Troy Hunt's Blog
Microsoft Security Blog
Microsoft Security Blog
SecWiki News
SecWiki News
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - nerozhang

NHibernate小结(一) 数据库字符串处理 数据库中的字符串操作 通过查询语句链接到远程数据库 得到数据库表的结构 从两张表中取出不一致的数据 NHibernate Quick Start Guide 唐诗赏析--唐诗的起源,发展 AggregateCacheDependency、CacheDependency、SqlCacheDependency Asp.net 2.0和PetShop4 的缓存示例 自定义 HttpModule 示例 在global.asax中实现URL重写(应用) Community Starter Kit - 结构 Community Starter Kit - 功能介绍 Community Starter Kit -简介 Petshop 4.0学习-MasterPage.master文件 PetShop 4.0学习-数据访问层之数据库访问设计 PetShop 4.0学习--登录以及注册功能的分析 PetShop 4.0学习--体系架构 PetShop 4.0学习--业务功能介绍
PetShop 4.0的缓存处理
nerozhang · 2007-08-24 · via 博客园 - nerozhang

    在访问量非常大,但更新较少的网站中使用缓存,可以大大提高程序运行的效率,给网络用户一个良好的体验效果。在Microsoft提供的经典示例项 目.Net PetShop 4.0中,也提供了对缓存的支持,本文是作者在学习此项目时的一些心得体会,有一些地方还不十分清楚,希望能够抛砖引玉。

    在.Net PetShop 4.0中,非常成功地使用了工厂模式以及接口(interface)、静态类(Static class)、抽象类(abstract class)等成员。在使用缓存时,也是通过web.config配置进行设置,在使用时非常灵活。下面从底向上具体分析.Net PetShop 4.0缓存方面的技术。

    首先看一下该项目中与缓存直接相关的命名空间:

PetShop.ICacheDependency
PetShop.TableCacheDependency
PetShop.CacheDependencyFactory
PetShop.Web

一、PetShop.ICacheDependency命名空间

   最低层应该是接口的定义了,在PetShop.ICacheDependency命名空间中只定义了一个接口 IPetShopCacheDependency,该接口只有一个方法 GetDependency,没有任何参数,返回AggregateCacheDependency类型。 AggregateCacheDependency是在.NET Framework 2.0 版中是新增的类,组合 ASP.NET 应用程序的 Cache 对象中存储的项和 CacheDependency 对象的数组之间的多个依赖项(MSDN中原话)。

二、PetShop.TableCacheDependency命名空间

  

PetShop.TableCacheDependency命名空间中,提供两种类:抽象类TableDependency和它的继承类CategoryItemProduct。抽象类TableDependency的构造函数为:

 1 protected TableDependency(string configKey) {
 2 
 3     string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];
 4     string tableConfig = ConfigurationManager.AppSettings[configKey];
 5     string[] tables = tableConfig.Split(configurationSeparator);
 6 
 7     foreach (string tableName in tables)
 8         dependency.Add(new SqlCacheDependency(dbName, tableName));
 9 }
10 

   传递了一个参数configKey,根据该参数从web.config文件中获取表名列表,同时在web.config中获取数据库名称。将表名列表中的所有数据表添加到AggregateCacheDependency类型的dependency变量中。在此外使用了.NET Framework 2.0 版中是新增的另一个与缓存有关的SqlCacheDependency类。这个类用于建立ASP.NET应用程序的Cache对象中存储的项和特定SQL Server数据库表之间的联系。AggregateCacheDependencySqlCacheDependency都从 CacheDependency继承而来,但在.NET 2.0中还未提供Oracle等其它数据库对应的类。   下面是web.config文件中与缓存相关的设置:

1 <!-- Cache dependency options. Possible values: PetShop.TableCacheDependency for SQL Server and keep empty for ORACLE -->
2 <add key="CacheDependencyAssembly" value="PetShop.TableCacheDependency"/>
3 <!-- CacheDatabaseName should match the name under caching section, when using TableCacheDependency -->
4 <add key="CacheDatabaseName" value="MSPetShop4"/>
5 <!-- *TableDependency lists table dependency for each instance separated by comma -->
6 <add key="CategoryTableDependency" value="Category"/>
7 <add key="ProductTableDependency" value="Product,Category"/>
8 <add key="ItemTableDependency" value="Product,Category,Item"/>
9 

   每个继承类都只有一个构造函数,通过设置基类的configKey参数变成了三个不同的类。Product类的构造函数为:

public Product() : base("ProductTableDependency") { }

三 CacheDependency工厂

    继 承了抽象类TableDependency的Product、Category和Item类均需要在调用时创建各自的对象。由于它们的父类 TableDependency实现了接口IPetShopCacheDependency,因而它们也间接实现了 IPetShopCacheDependency接口,这为实现工厂模式提供了前提。

   在PetShop 4.0中,依然利用了配置文件和反射技术来实现工厂模式。命名空间PetShop.CacheDependencyFactory中,类DependencyAccess即为创建IPetShopCacheDependency对象的工厂类:

 1 public static class DependencyAccess
 2 {       
 3     public static IPetShopCacheDependency CreateCategoryDependency()
 4     {
 5         return LoadInstance("Category");
 6     }
 7     public static IPetShopCacheDependency CreateProductDependency()
 8     {
 9         return LoadInstance("Product");
10     }
11     public static IPetShopCacheDependency CreateItemDependency()
12     {
13         return LoadInstance("Item");
14     }
15     private static IPetShopCacheDependency LoadInstance(string className)
16     {
17         string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
18         string fullyQualifiedClass = path + "." + className;
19         return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
20     }
21 }

    在这个方法中通过配置文件中的设置和传进来的参数className,返回相对应的程序集和类。DependencyAccess类里面的其它三个方法,只是调用这个方法,传入不同的参数而已。

整个工厂模式的实现如图4-3所示:


  

DependencyFacade 类提供的三个方法正好与DependencyAccess类的三个方法相对应,分别获取CategoryItemProduct AggregateCacheDependency。在DependencyFacade类中还读取了web.config中的 CacheDependencyAssembly设置,从而决定是调用DependencyAccess对应的方法,还是直接返回null

 1 public static class DependencyFacade
 2 {
 3     private static readonly string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
 4     public static AggregateCacheDependency GetCategoryDependency()
 5     {
 6         if (!string.IsNullOrEmpty(path))
 7             return DependencyAccess.CreateCategoryDependency().GetDependency();
 8         else
 9             return null;
10     }
11     public static AggregateCacheDependency GetProductDependency()
12     {
13         if (!string.IsNullOrEmpty(path))
14             return DependencyAccess.CreateProductDependency().GetDependency();
15         else
16             return null;
17         }
18     public static AggregateCacheDependency GetItemDependency()
19     {
20         if (!string.IsNullOrEmpty(path))
21             return DependencyAccess.CreateItemDependency().GetDependency();
22         else
23             return null;
24     }
25 }
26 

     DependencyFacade类封装了获取AggregateCacheDependency类型对象的逻辑,如此一来,调用者可以调用相关方法获得创建相关依赖项的AggregateCacheDependency类型对象:

1 AggregateCacheDependency dependency = DependencyFacade.GetCategoryDependency();

   比起直接调用DependencyAccess类的GetDependency()方法而言,除了方法更简单之外,同时它还对CacheDependencyAssembly配置节进行了判断,如果其值为空,则返回null对象。  虽然DependencyAccess类创建了实现了IPetShopCacheDependency接口的类Category、Product、 Item,然而我们之所以引入IPetShopCacheDependency接口,其目的就在于获得创建了依赖项的 AggregateCacheDependency类型的对象。

四、PetShop.Web命名空间
   在PetShop.Web App_Code中,有四个静态类与缓存直接相关,分别是CategoryDataProxyItemDataProxy ProductDataProxyWebUtility。其中前三个分别调用DependencyFacade对应的方法。例如GetCategoryName()方法:

 1 public static string GetCategoryName(string categoryId)
 2 {
 3      Category category = new Category();
 4      if (!enableCaching)
 5             return category.GetCategory(categoryId).Name;
 6      string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);
 7      // 检查缓存中是否存在该数据项;
 8      string data = (string)HttpRuntime.Cache[cacheKey];
 9      if (data == null)
10      {
11            // 通过web.config的配置获取duration值;
12            int cacheDuration = int.Parse(ConfigurationManager.AppSettings["CategoryCacheDuration"]);
13            // 如果缓存中不存在该数据项,则通过业务逻辑层访问数据库获取;
14            data = category.GetCategory(categoryId).Name;
15            // 通过Facade类创建AggregateCacheDependency对象;
16            AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency();
17            // 将数据项以及AggregateCacheDependency 对象存储到缓存中;
18            HttpRuntime.Cache.Add(cacheKey, data, cd, DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
19       }
20       return data;
21 }
22 

   GetCategoryName ()方法首先会检查缓存中是否已经存在CategoryName数据项,如果已经存在,就通过缓存直接获取数据;否则将通过业务逻辑层调用数据访问层访问 数据库获得CategoryName,在获得了CategoryName后,会将新获取的数据连同DependencyFacade类创建的 AggregateCacheDependency对象添加到缓存中。
     WebUtility静态类被表示层的许多页面所调用,例如Product页面:

1 public partial class Products : System.Web.UI.Page
2 {
3     protected void Page_Load(object sender, EventArgs e)
4     {
5         Page.Title = WebUtility.GetCategoryName(Request.QueryString["categoryId"]);
6     }
7 }

  
     显示页面
title的逻辑是放在Page_Load事件方法中,因而每次打开该页面都要执行获取CategoryName的方法。如果没有采用缓存机制,当Category数据较多时,页面的显示就会非常缓慢。
   显示页面title的逻辑是放在Page_Load事件方法中,因而每次打开该页面都要执行获取CategoryName的方法。如果没有采用缓存机制,当Category数据较多时,页面的显示就会非常缓慢。