ASP.NET 中的 Page Cache 是个很有用的东东,只要简单的在页面上方加上一个 OutputCache 标签,就可以让页面在制定的 Duration 内直接把自动保存在缓存中的页面内容输出,而不需要让 ASP.NET 引擎再次执行页面代码,当然,节省这点执行时间并不是最主要的理由,主要理由是如果页面内容是从数据库中取出,那么就可以省去连接数据库、取数据的步骤,这个好处可大了。
PageCache 有点小小的问题,比如,很多 ASP.NET 论坛的首页就用了 PageCache ,所以在一个版里面贴出的最新的帖子并不会马上反映到首页上,而是需要等上一段时间。虽然有点无可奈何,但在某些场合(比如易趣用来显示物品拍卖状态的页面),这种延迟是不允许的。
也即是说, ASP.NET 里面的 Cache 并不能自动根据数据库中相应数据发生了变化,而使相应的 Cache 过期, ASP.NET 2.0 中新增的 SqlCacheDependency 特性使这成为了可能。(当然,只要我们明白了 ASP.NET 2.0 中的大致实现方式,我们可以基于 ASP.NET 1.0 把这个特点实现出来,后面我总结了相应的方法。)
要在 ASP.NET 2.0 中应用 SqlCacheDependency 特性,步骤如下(基于大家手里的 Whidbey PDC 版本):
1、
使数据库支持
SqlCacheDependency
在
.Net Framework 1.2
的安装目录下(通常是
WINDOWS\Microsoft.NET\Framework\v1.2.30703
),有一个
aspnet_regsqlcache.exe
,这个命令行工具让我们的
SqlServer 7.0
或者
SqlServer 2000
能支持
SqlCacheDependency
特性,
首先:“
aspnet_regsqlcache –S
服务器名称
–U
登陆
ID –P
密码
–d
数据库名称
–ed
”,这个命令使指定数据库支持
SqlCacheDependency
,
然后我们再加入要追踪的数据表:“ aspnet_regsqlcache –S 服务器名称 –U 登陆 ID –P 密码 –d 数据库名称 –t 要追踪的数据表的名称 –et ”,这个命令使指定的 Table 支持 SqlCacheDependency 。
它在幕后做了什么事情呢?
首先,它在指定的数据库中新建了一个 Table ,叫做“ AspNet_SqlCacheTablesForChangeNotification ”,这个表有三个字段,“ tableName ”记录要追踪的数据表的名称,“ notificationCreated ”记录开始追踪的时间,“ changeId ”是一个 int 类型的字段,每当追踪的数据表的数据发生变化时,这个字段的值就加 1 。
它还会在指定的数据库中增加几个存储过程,用来让 ASP.NET 引擎查询追踪的数据表的情况。
然后,它会给我们要追踪的 Table 加上几个 Trigger ,分别对应到 Insert 、 Update 、 Delete 操作,这几个 Trigger 的语句非常简单,就是把“ AspNet_SqlCacheTablesForChangeNotification ”表中对应“ tableName ”字段为这个追踪的表的名称的记录的“ changeId ”字段加上一个 1 。
ASP.NET 引擎通过执行它加上的存储过程“ AspNet_SqlCachePollingStoredProcedure ”,这个存储过程直接返回“ AspNet_SqlCacheTablesForChangeNotification ”表的内容,让 ASP.NET 引擎知道哪个表的数据发生的变化。默认每 500 毫秒执行这个存储过程一次,不过可以在 web.config 里面修改这个间隔时间,我的经验是这个查询操作也是很耗资源的,呵呵。
2、
web.config
配置
在 web.config 里面的配置再简单不过了
<configuration>
<!-- 加上合适的数据库连接字符串 -->
<connectionStrings>
<add name="SqlServerConnectionString"
connectionString="server=sqlserver1;uid=sa;pwd=
password;database=PortalDB " />
</connectionStrings>
<system.web>
<!--
配置
Cache
一段,使之支持
SqlCacheDependency -->
<cache>
<sqlCacheDependency enabled="true" pollTime="500">
<databases>
<add name=" PortalDB "
connectionStringName=" SqlServerConnectionString " />
</databases>
</sqlCacheDependency>
</cache>
</system.web>
</configuration>
3、
在页面上的
outputCache
标签中指定
SqlCacheDependency
特性:
<%@ outputcache duration="9999" varybyparam="None" sqldependency="PortalDB: 追踪的数据表名称 " %>
只要在这个追踪的 Table 上执行了 Insert 、 Update 、 Delete 操作,数据表上的 Trigger 就会将数据库中“ AspNet_SqlCacheTablesForChangeNotification ”表的相应记录的相应“ changId ”字段值修改,然后 ASP.NET 引擎就会通过获取新的值来得知追踪的 Table 的内容发生了变化,自动使这个页面的 cache 失效。
后话
1
、
What about Yukon
?
从上面可以知道, SqlServer 并没有内置自动追踪数据表的数据变化,然后通知 ASP.NET 引擎的功能(这是肯定的, SqlServer 都出来 N 久了),所以 ASP.NET 2.0 的开发组人为的加上了定制的 Table 、 Trigger 、 StoredProcedure 等等来实现数据更改追踪。而 Yukon 已经不必这么麻烦了, Yukon 内置了一个 Notification Delivery Service ,这个服务会通过 WebServer 的 80 端口直接通知一个 IIS 内置的监听器,然后这个监听器再通知 ASP.NET 。
而且大家可以注意到,上面描述的那种追踪方式只能追踪到表一级的数据更改,即 ASP.NET 引擎最后只能得知某个表的数据发生了更改,而到底是哪一条记录发生了更改,是追踪不到的,而 Yukon 的 Notification Delivery Service 可以实现记录一级的追踪。
后话
2
、可以在现在的
ASP.NET
上实现吗?
当然可以,我们先按照上面讲的第一个步骤(或者自己定义一套规则来实现在数据库中对 Table 数据变化的追踪),依照葫芦画瓢来自己添加上这些 Table 、 Trigger 什么的。
ASP.NET 的 PageCache 有一个 VaryByCustom 属性的,这个属性可以实现让我们自己定义“缓存过期”的规则(确切的说,其实它是可以让我们自定义缓存页的版本,但间接可以实现自定义的缓存“过期”啦,呵呵),只要我们在 global.asa 中重写 HttpApplication.GetVaryByCustomString() 方法,这个方法根据输入的参数字符串,比如“ CheckDBTable=Users ”,查询数据库中那个“ AspNet_SqlCacheTablesForChangeNotification ”(或者你自己定义的某个追踪记录表),直接让这个 GetVaryByCustomString() 方法返回“ changeId ”字段的值即可。 VaryByCustom 的用法 MSDN 文档上有详细说明。
后话
3
、
GolfClubShack
示范程序
在博客堂前面的某篇文章里面,提供了一个基于
ASP.NET 2.0
的
GolfClubShack
站点的示范程序,是非常好的东东,在那个里面可以看到包括
SqlCacheDependency
在内的众多
ASP.NET 2.0
的特性的体现。现在网上完整的
ASP.NET 2.0
的示范程序不多,听说
MS
内部已经把
IBuySpy
移植到
ASP.NET 2.0
上面了,不知详情如何。而
MS
还在
alpha
阶段的
AspNetForums 2.0
还是基于
.Net Framework 1.1
的(我以前一直是以为是基于最新的
ASP.NET 2.0
的,安装了好半天,晕
...
)。