概述
任何有实际价值的关系数据库应用程序都离不开一大堆的查询表。如果您是开发图形用户界面的专家,那么您知道这些查询表将用于加工下拉列表框中的列表。我将查询表分成两种:只读表和可改写只读表。二者的区别在于什么会导致表的改变。我认为如果需要召开员工会议或者用户会议才可以修改表的内容,那么表就是只读的。一个好的例子就是公司的产品类别表。表的内容将不会改变直到公司研发并向市场投放了新产品,或者公司进行了重组。可改写的只读表是内容相对固定的列表,但可以被最终用户修改,通常使用组合框而不用下拉列表框来展现。可改写只读表的一个例子就是称谓术语表。应用程序设计人员能够考虑到最常用的那些称谓,如Ms., Mr., Mrs.以及Dr.,但总有某个用户的头衔是您从未考虑过的而且希望把它添加进来。举个例子看看这种情况有多么常见,我最后工作的一个中型产品有一个设计良好符合第三范式的关系数据库,它包含了350—400张表,我估计了一下大约有250张表是只读的或可改写只读表。
传统的Web应用程序(三层结构应用程序的经典范例)希望尽可能地缓存这种类型的表。这样不仅可以减少往返数据库的次数,还可以降低数据库服务器的查询负载、提高某些应用场景的响应能力,例如接受了新订单。只读表很容易缓存;可以始终将表放在缓存中,偶尔需要重新加载表时,则由数据库管理员(DBA)通过某种方式重新加载缓存。我希望您的企业中很少召开对数据库基本结构和内容作修改的会议。重新刷新中间层缓存中可改写只读表则有一点点麻烦。如果缓存刷新的频率太低就无法获得您期望的效果;用户也无法立刻看到其它用户对数据的修改。支持人员可以使用另一个应用程序添加新项,然后给打算使用该项的同伴发送一条即时消息,但同伴的选择列表框中却并不包含新添加的项。更糟糕的是,如果第二个用户此时试图重新添加这条“缺失的列表项”,就会收到一条数据库错误告知该项已经存在了。由于类似问题的存在,如果可改写只读表允许多点更新,那么通常不进行缓存。
过去,程序员不得不自己手工开发解决方案,使用消息队列、进行文件输出的触发器、或者out-of-band协议来通知缓存,如果应用程序外部的某些用户更新了可改写只读表。这种“通知”解决方案只是通知缓存有行被添加或修改了,指示必须刷新缓存。如何通知缓存有哪些行改变了或者有哪些行被添加了,这一直都是个难题,是分布式数据库和分布式事务或者合并复制领域的问题。低成本的通知解决方案的做法是:只要程序收到“缓存无效“的消息就刷新整个缓存。
SqlDependency 提供了缓存解决方案
如果您正在使用SQL Server 2005和ADO.NET 2.0,那么一种新的称为查询通知的通知解决方案已内置在SqlClient数据供应商和数据库中。该问题终于有了内置且易于使用的解决方案!ASP.NET 2.0也内置了用于支持查询通知的特性。ASP.NET的Cache对象可以注册通知,甚至还可以将通知与ASP.NET的页面缓存或页面片段缓存结合在一起使用。
实现该功能的架构中包含了SQL Server 2005查询引擎、SQL Server Service Broker、sp_DispatcherProc系统存储过程,ADO.NET的SqlNotification (System.Data.Sql.SqlNotificationRequest)和SqlDependency类(System.Data.SqlClient.SqlDependency),以及ASP.NET的Cache类(System.Web.Caching.Cache)简而言之,它的工作方式如下:
1.每个ADO.NET SqlCommand都包含一个Notification属性,表示对通知的请求。
当执行SqlCommand时,如果存在Notification属性,那么就会在网络请求中附加一个表示通知请求的网络协议包(TDS)。
2.SQL Server使用查询通知架构注册所请求通知的订阅,然后执行命令。
3.SQL Server“监视”任何可能导致最初返回的结果集发生变化的SQL DML语句。当发生变生时,就向Service Broker服务发送消息。
4.消息可以:
a.引发通知并将通知传回注册的客户端。
b.驻留在Service Broker's的服务队列中,高级客户端可以实现自己的处理机制。
图1. 通知服务概览