5

我经常以以下形式运行查询:

select * from SomeTable where id=12345

一页又一页我可能正在运行相同的查询,因为用户需要该行的值。通常我会获取一次并缓存它,但是用户可以随时更改行,其他用户也在同时在 SomeTable 中进行更改,因此我无法缓存整个表。我还有一个问题,我们有一个网络服务器集群,所以当缓存失效时,我无法在网络服务器上进行内部跟踪。

有没有办法检测到这一行发生了变化?SqlDependecyCache 类可以在这里为多个 Web 服务器的单个行提供帮助吗?是否有一些触发器或其他范例可以通知我的 Web 应用程序?

我想要两全其美 - 网络服务器上的实时缓存更新,但我不想运行任何查询来查看该行是否已更改,因为我可以轻松地再次获取该行。

4

2 回答 2

3

您需要的是启用 SqlCacheDependency 正如@RenusRusanu 提到的那样。

我的 Github 网站上有几个工作示例,请随意浏览 我的 LearningProjects 下的代码第 3 方编辑

您需要先配置数据库才能使用 SqlCacheDependency:

为了使用 SQL Dependency,我们需要在数据库中基本配置两件事:

  1. 创建包含在表上的数据库基础结构并存储过程,要对其进行配置,我们使用aspnet_regsql.exe如下:

    /* For SQL Server authentication... */
    aspnet_regsql.exe -S server -U user -P password -d database -ed
    /* For Windows Authentication... */
    aspnet_regsql.exe -S server -E -d database -ed
    
  2. 创建轮询信息,其中包括指定要监视的表和对该表的触发器以填充所需的基础结构表

        /* For SQL Server authentication... */
            aspnet_regsql.exe -S server
           -U user -P password -d database -t tableName -et
            /* For Windows Authentication... */
           aspnet_regsql.exe -S server
           -E -d database -t tableName -et
    

代码配置

        var s = new SqlCacheDependency("AdventureWorks", "Product");

        HttpContext.Current.Cache.Insert(
            "products", 
            h, 
            s, 
            Cache.NoAbsoluteExpiration, 
            Cache.NoSlidingExpiration);

AdventureWorks名称为web.config文件中配置的sql依赖的名称

<caching>
  <sqlCacheDependency enabled="true" pollTime="30000" >
    <databases>
      <add 
           name="AdventureWorks"
           connectionStringName="AdventureWorksPolling" />
    </databases>
  </sqlCacheDependency>
</caching>

pollTime可以在元素中配置,并将<add ...覆盖全局polltime

或者,您可以依赖 SqlDataSource 控件

为了在使用此控件时启用缓存,您需要将DataSourceMode属性设置为DataSet. 在这种情况下,您不需要像前面解释的那样配置数据库

我刚刚上传了这个例子(完整的工作例子)

ASPX

    <asp:SqlDataSource runat="server" ID="sds"
        ConnectionString="<%$ConnectionStrings:pubsConnectionString %>"
        CacheDuration="30"
        EnableCaching="true"
        SelectCommand="select * from jobs"
        DataSourceMode="DataSet"
        OnSelecting="sds_Selecting">

    </asp:SqlDataSource>
    <div>
        <asp:Literal runat="server" ID="msg" Mode="Encode"></asp:Literal>
    </div>
    <asp:GridView runat="server" DataSourceID="sds"></asp:GridView>

编辑 1

为了在使用 SqlCacheDependency 时有选择地触发触发器,您需要更新手动生成的触发器。

使用该aspnet_regsql -t -et...命令配置表时,会在指定表中添加触发器。此触发器负责填充AspNet_SqlCacheTablesForChangeNotificationSqlCacheDependency 对象使用的表,以轮询数据库中的数据。

触发器看起来像:

ALTER TRIGGER [dbo].[jobs_AspNet_SqlCacheNotification_Trigger] ON [dbo].[jobs]
                   FOR INSERT, UPDATE, DELETE AS BEGIN
                   SET NOCOUNT ON
                   EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure N'jobs'
                   END

dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedureN'jobs'当您感兴趣的行更新时,您可以更新触发器以仅调用存储过程

我不是 SQL 专家,但我认为很容易找到一种干净的方法来检测已更改的行,例如,谷歌搜索我刚刚找到了这个链接

在 MS SQL Server 中检测列更改的最有效方法

于 2012-09-14T12:14:32.197 回答
2

SqlCacheDependency, 以及SqlDependency, 可以完全按照您的描述进行。两者都基于Query Notifications,一种允许您的应用程序在更新行时从服务器接收通知的技术。您甚至可以从LINQ中利用它。

但是您需要小心,缓存频繁更改的值可能弊大于利。您应该只对相当稳定的值执行此操作。

于 2012-09-14T11:57:12.483 回答