
2008年4月16日
Scott Mitchell谈DataSource系列之七声明式缓存数据
Accessing and Updating Data in ASP.NET 2.0: Declaratively Caching Data
By Scott Mitchell
原文地址:Declaratively Caching Data
前言
ASP.NET 2.0数据源控件提供一种声明式访问和处理数据的手段。简单地配置一下控件的几个属性就可将数据绑定到数据控件.这样甚至不用手写一行代码,就实现了检索和处理数据。
除了可以声明式处理数据,这些数据源控件还可以实现声明式缓存数据. 缓存通常应用于一些数据驱动的应用程序以提高性能,它的基本工作原理是将数据存储到内存中,这样可以大大提高数据的访问效率. ASP.NET支持数据缓存,可以通过编程方式来访问存储于其中的数据库查询结果.可以到 ASP.NET中的缓存 查看有关缓存以及ASP.NET的其他缓存机制.
值得一提的是,数据源控件提供声明式访问数据缓冲区. 只需简单地设置几个属性,数据源控件就会轻松地将检索到的数据存储到数据缓冲区.然后,当再次向数据源检索数据时, 它们就可以直接从缓存中读取,而不是再次到数据库中检索.本文将介绍如何使用数据源控件的缓存特性.
缓存快速入门
缓存是一种提高性能的技术,它把数据从比较”昂贵”的数据存储转到相对低廉的存储形式.这里我所说的”昂贵”是指处理数据所带来的性能损失,”数据存储”是指数据存储的方式,比如数据库,文件或者内存等.典型的缓存案例是将从数据库检索到的数据存储到应用程序内存中,因为应用程序从内存中读取数据的速度要比远程读取数据库快好几个数量级.
缓存技术也有一些局限性.效率较高的数据存储占用的空间较小. 也就是说, 尽管数据库中有大量的数据,但能够存储在应用程序缓存中的只占其中很小的一部分. 因此,并非所有数据都可以实现缓存.而且当向缓存区写入数据时,有些其他缓存数据就要被清除,腾出点地儿来.
而且, 缓存会强制断开应用程序“看到的”数据和真实的数据源之间的连接。如果真实的数据源被修改或删除,使用缓存数据的应用程序将不会判别出它持有的数据已经作废,除非它再次访问数据源。因此,通常情况下数据在预定的时间内缓存,然后会自动被清除。这样便存在着数据过期的一个时间上限。 (ASP.NET 2.0 支持 SQL 缓存依赖,该技术可以更“主动”地判断缓存数据是否过期。本文对SQL 缓存依赖不作深入探讨,详情请查看文末的“延伸阅读”。)
缓存是ASP.NET 应用程序中经常使用的技术之一,它是将数据存储在内存中,可以通过Cache对象来访问。缓存提供类似字典的访问机制。在缓存区添加一个新项,只需为该项指定一个string类型的键。同理,要从缓存中获取数据,只需通过它的键来获得。下面的代码段展示了如何读写缓存中的数据:
|
// C#
Cache["key"] = ObjectToCache; // 写入缓存
object myData = Cache["key"]; // 从缓存中读出
' VB
Cache("key") = ObjectToCache ' 写入缓存
Dim myData As Object = Cache("key") ' 从缓存中读出
|
数据源控件检索缓存数据
ObjectDataSource, SqlDataSource, AccessDataSource以及 XmlDataSource这几个控件都包含如下支持缓存的几个主要属性。缓存是自动发生的,无须开发人员编写代码。它们的主要属性如下:
- EnableCaching – 一个布尔值,表示是否应用缓存,默认为False。可以将其设置为True来启用缓存。
- CacheDuration – 一个Integer类型的值,获取或设置以秒为单位的一段时间。它是数据源控件缓存Select方法所检索到的数据的时间。
- CacheExpirationPolicy - 获取或设置缓存的到期行为,该行为与持续时间组合在一起可以描述数据源控件所用缓存的行为,可以设置为Absolute或Sliding。Absolute 表示缓存项从数据存入缓存区开始经过CacheDuration秒后被清除;Sliding表示缓存项自缓存数据被访问的时间开始,经过CacheDuration秒后被清除,它的默认值是Absolute。
- CacheKeyDependency – 是个String类型的值,表示获取或设置一个用户定义的键依赖项,该键依赖项链接到数据源控件创建的所有数据缓存对象。当键到期时,所有缓存对象都显式到期。
如果启用了SQL缓存依赖,那么就要使用SqlDataSource和ObjectDataSource控件的SqlCacheDependency属性。还有一点要记住, AccessDataSource控件没有这一属性,如果试图使用将会引发一个NotSupportedException异常。最后还要记住,若要这些数据源控件启用缓存,必须将EnableCaching属性设为True,并且通过CacheDuration指定一个过期时间或者指定一下SQL缓存依赖。
下面的声明式代码段展示了一个启用缓存并将过期时间设为30秒的AccessDataSource 控件(在本文最后提供下载的示例代码中还有更多相关demo):
|
<asp:AccessDataSource ID="ProductsDataSource" runat="server"
DataFile="~/App_Data/Northwind.mdb"
SelectCommand="SELECT * FROM [Products]"
CacheDuration="30"
EnableCaching="True">
</asp:AccessDataSource>
|
当数据控件(比如GridView)触发了该AccessDataSource控件的Select方法后, AccessDataSource 会首先查看数据是否在缓存区。如果不是,它才会连接Microsoft Access数据库(Northwind.mdb),并执行SelectCommand的查询,然后它会把7ED3果存储到缓存区,再将其交给数据控件。假设5秒钟后另一个用户访问该页面,数据控件会再次向AccessDataSource 发出数据请求,不过这次数据将会在缓存区。因此, AccessDataSource 无需访问数据库而直接把缓存中的数据交给数据控件。但是30秒钟后,缓存区中的数据将会被清除,后续的数据请求将会连接到数据库。
数据源实现数据缓存之细节探究
当启用了缓存的数据源控件被触发了Select方法时,它会首先检查数据是否存放在缓存区。之前已经提过,缓存中的数据项是通过一个string类型的键来访问的,数据源控件使用的这个键值是它一系列属性的集合。比如SqlDataSource,它包括CacheDuration, CacheExpirationPolicy, ConnectionString, SelectCommand, 以及SelectParameters这些属性的值。这样可以保证每个连接,每个SELECT查询及其查询的参数名和值(如果有)的唯一性。
在缓存区发现了数据项后,数据源控件将会返回这些数据,不去触发它的Selecting事件。我在了解数据源控件的事件机制这篇文章中已经提过,在数据源控件触发Select方法并从数据库中检索出数据后,Selecting事件才会被激发。
而如果在缓存中没有找到数据项,数据源控件就会按照常规方式进行查询:Selecting事件被触发,然后访问数据库,检索数据,最后是触发Selected事件。但是在数据返回前,数据源控件会首先将其添加到缓存,过程如同上面的介绍。
下面的流程图描述了ObjectDataSource的缓存工作流程,AccessDataSource, SqlDataSource和 XmlDataSource控件也都一样。注意如果数据项在缓存中,那么Selecting事件便不会被触发。

可以看出,Selecting事件只有从数据库中访问数据时才会发生,这也是上一次缓存发生的时间。文末的代码示例使用了一个Label 控件,该控件的值根据Selecting事件的每次发生而更改为当前的日期和时间,因此它可以显示缓存最近的一次修改发生的时间。尽管最终用户可能不需要也没必要看到这种信息,但这对页面开发人员却非常有用,因为它可以显示缓存发生的时间以及什么行为可以使缓存比预期时间更早地被清除。
清除缓存中的数据
缓存的一大弊端就是过期数据,短时间的过期策略可以有效地限定潜在的过期数据的持续时间。也有其他的方法来强行将一个数据项从缓存中清除,这就是数据源控件的Insert, Update, 和Delete事件,他们一旦被调用,控件将会自动清除掉它们的缓存数据。在接下来的文章中,我们会详细探讨数据源控件中可用的这些数据修改方法。总之,这些方法修改数据库中的数据,并且—正像他们的名称表示的那样—可以声明式地配置。当这些方法执行时,数据源控件修改的是数据库中的数据,所以数据源控件将会清除缓存,因为缓存数据已经过期了。你可以在文末的代码示例中查看。
还可以通过编程方式使用CacheKeyDependency属性清除数据源控件的缓存数据。将该属性的值设置为缓存数据中的某个键值,然后,只需修改一下CacheKeyDependency的值即可清除该数据源控件中的缓存数据。
更改数据源控件的CacheKeyDependency属性为你想设为依赖项的缓存键的名称,比如可以将该属性的值设为一个过时的变量:
|
<asp:AccessDataSource ID="ProductsDataSource" runat="server"
DataFile="~/App_Data/Northwind.mdb"
SelectCommand="SELECT * FROM [Products]"
CacheDuration="30"
EnableCaching="True"
CacheKeyDependency="ProductsDependency">
</asp:AccessDataSource>
|
接着,必须解决的是该确定是否有数据项存在于缓存中。否则一旦有数据项添加到缓存时就会清除数据源控件的原有缓存数据。在Page_Load事件中,判断该项是否存在于缓存;如果没有,则添加之:
|
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
'添加缓存项,如果需要的话
If Cache(ProductsDataSource.CacheKeyDependency) Is Nothing Then
Cache(ProductsDataSource.CacheKeyDependency) = DateTime.Now
End If
End Sub
|
这里我将DateTime.Now赋给缓存项,不过你可以使用其他任意值.DateTime.Now是个不错的选择,因为它可以表示该缓存项上次被访问的时间.
若要通过编程方式清除缓存数据,只需修改一下Cache(ProductsDataSource.CacheKeyDependency)的缓存值即可,比方说修改为当前的日期和时间(Cache(ProductsDataSource.CacheKeyDependency) = DateTime.Now). 本文最后附上的demo中,页面上的按钮被点击后,触发事件将Cache(ProductsDataSource.CacheKeyDependency)的值修改为当前的日期和时间,这样就可以清除缓存数据了.就是这么简单!
小结
数据源控件访问和操作数据简单得只需设置几个属性,通常情况下无需手写代码。在本文中我们可以看到,声明式同样适用于缓存。在数据源控件中应用缓存很简单,只需将该控件的EnableCaching属性设为True,将CacheDuration属性设置为数据缓存持续的时间(秒)。SqlDataSource和ObjectDataSource控件还支持缓存依赖,我将在以后的文章中介绍这些特性。
祝编程愉快!
· By Scott Mitchell
延伸阅读
· 缓存之于性能
· ASP.NET 2.0缓存特性 (包括SQL缓存依赖)
· ASP.NET 缓存:方法和最佳实践
· [视频] ASP.NET2.0中的缓存
附件
· 下载本文的示例代码
posted @ 2008-04-16 16:29 小白杨 阅读(251) 评论(0)
编辑