使用 SQL 快取相依性 (VB)

作者 :Scott Mitchell

下載 PDF

最簡單的快取策略是允許快取的數據在指定的時間之後過期。 但是這個簡單方法表示快取的數據與其基礎數據源沒有關聯,導致保留太長或目前數據太快過期的數據。 更好的方法是使用 SqlCacheDependency 類別,讓數據保持快取狀態,直到其基礎數據已在 SQL 資料庫中修改為止。 本教學課程會完整說明。

簡介

在架構教學課程中使用 ObjectDataSource快取數據 快取數據中檢查的快取技術,使用以時間為基礎的到期日,在指定的期間後從快取收回數據。 這種方法是平衡快取與數據過時效能提升的最簡單方式。 藉由選取 x 秒的時間到期,頁面開發人員會嘗試只享有 快取 x 秒的效能優勢,但可以輕易地讓數據永遠不會超過 x 秒上限。 當然,對於靜態數據, x 可以延伸至 Web 應用程式的存留期,如在 應用程式啟動時 快取數據教學課程中所述。

快取資料庫數據時,通常會選擇以時間為基礎的到期日,以方便使用,但通常是不足的解決方案。 在理想情況下,資料庫數據會保持快取狀態,直到基礎數據已在資料庫中修改為止;只有之後才會收回快取。 此方法可將快取的效能優勢最大化,並將過時數據的持續時間降到最低。 不過,為了享有這些優點,必須具備一些系統,知道基礎資料庫數據何時經過修改,並從快取收回對應的專案。 在 ASP.NET 2.0 之前,頁面開發人員必須負責實作此系統。

ASP.NET 2.0 提供 SqlCacheDependency 類別 和必要的基礎結構,以判斷資料庫中何時發生變更,以便收回對應的快取專案。 有兩種技術可用來判斷基礎數據何時變更:通知和輪詢。 討論通知和輪詢之間的差異之後,我們將建立支援輪詢所需的基礎結構,然後探索如何在宣告式和程序設計方式案例中使用 SqlCacheDependency 類別。

瞭解通知和輪詢

有兩種技術可用來判斷資料庫中的數據何時已修改:通知和輪詢。 透過通知,資料庫會在上次執行查詢之後變更特定查詢的結果時,自動警示 ASP.NET 運行時間,此時會收回與查詢相關聯的快取專案。 使用輪詢,資料庫伺服器會維護上次更新特定數據表的相關信息。 ASP.NET 運行時間會定期輪詢資料庫,以檢查哪些數據表在快取中輸入之後已變更。 已修改數據的數據表已收回其相關聯的快取專案。

通知選項的設定比輪詢少,而且更細微,因為它會追蹤查詢層級的變更,而不是在數據表層級追蹤變更。 不幸的是,通知僅適用於完整版本的 Microsoft SQL Server 2005 (,也就是非 Express 版本) 。 不過,輪詢選項可用於從 7.0 到 2005 的所有 Microsoft SQL Server 版本。 由於這些教學課程使用 express 版本的 SQL Server 2005,因此我們將著重於設定和使用輪詢選項。 如需 2005 年 2005 年通知功能 SQL Server 的進一步資源,請參閱本教學課程結尾的一節。

使用輪詢時,資料庫必須設定為包含名為 AspNet_SqlCacheTablesForChangeNotification 且具有三個資料行的數據表: tableNamenotificationCreatedchangeId。 此資料表包含每個數據表的數據列,這些數據可能需要用於 Web 應用程式中的 SQL 快取相依性。 數據 tableName 行會指定數據表的名稱,而 notificationCreated 表示數據列加入數據表的日期和時間。 數據 changeId 行的類型 int 為 ,且初始值為 0。 其值會隨著數據表的每個修改而遞增。

除了 AspNet_SqlCacheTablesForChangeNotification 數據表之外,資料庫也需要在每個可能會出現在 SQL 快取相依性中的數據表上包含觸發程式。 每當插入、更新或刪除資料列,並在 中AspNet_SqlCacheTablesForChangeNotification遞增數據表changeId的值時,就會執行這些觸發程式。

ASP.NET 運行時間會追蹤使用 SqlCacheDependency 物件快取數據時的數據表目前changeId。 系統會定期檢查資料庫,而且任何 SqlCacheDependency 與資料庫中值不同的物件 changeId 會收回,因為不同的 changeId 值表示自從快取數據之後,數據表已有變更。

步驟 1:探索aspnet_regsql.exe命令行程式

使用輪詢方法時,資料庫必須設定為包含上述基礎結構:預先定義的數據表 (AspNet_SqlCacheTablesForChangeNotification) 、少數預存程式,以及 Web 應用程式中可用於 SQL 快取相依性之每個數據表上的觸發程式。 您可以透過命令列程式建立這些資料表、預存程式和觸發程式,此程式 aspnet_regsql.exe位於 $WINDOWS$\Microsoft.NET\Framework\version 資料夾中。 若要建立 AspNet_SqlCacheTablesForChangeNotification 資料表和相關聯的預存程式,請從命令行執行下列命令:

/* 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

注意

若要執行這些命令,指定的資料庫登入必須位於 和 db_ddladmin 角色中db_securityadmin

例如,若要使用 Windows 驗證將輪詢的基礎結構新增至名為 之資料庫伺服器上名為 pubsScottsServer 的 Microsoft SQL Server 資料庫,請瀏覽至適當的目錄,然後從命令行輸入:

aspnet_regsql.exe -S ScottsServer -E -d pubs -ed

新增資料庫層級基礎結構之後,我們需要將觸發程式新增至將用於 SQL 快取相依性的數據表。 再次使用 aspnet_regsql.exe 命令列程式,但使用 -t 參數指定資料表名稱,而不是使用 -ed 參數, -et如下所示:

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

若要將觸發程式新增至 authors 上的 ScottsServer資料庫上的 pubstitles 數據表,請使用:

aspnet_regsql.exe -S ScottsServer -E -d pubs -t authors -et
aspnet_regsql.exe -S ScottsServer -E -d pubs -t titles -et

在本教學課程中,請將觸發程式新增至 ProductsCategoriesSuppliers 數據表。 我們將在步驟 3 中查看特定的命令行語法。

步驟 2:在 中參考 Microsoft SQL Server 2005 Express Edition 資料庫App_Data

aspnet_regsql.exe命令行程式需要資料庫和伺服器名稱,才能新增必要的輪詢基礎結構。 但位於 App_Data 資料夾中的 Microsoft SQL Server 2005 Express 資料庫的資料庫和伺服器名稱為何? 我發現最簡單的方法是將資料庫附加至localhost\SQLExpress資料庫實例,並使用 SQL Server Management Studio 重新命名數據,而不需要探索資料庫和伺服器名稱是什麼。 如果您的電腦上已安裝其中一個完整版本的 SQL Server 2005,則您可能已在電腦上安裝 SQL Server Management Studio。 如果您只有 Express 版本,您可以下載免費的 Microsoft SQL Server Management Studio

從關閉 Visual Studio 開始。 接下來,開啟 SQL Server Management Studio,然後選擇使用 Windows 驗證連線到localhost\SQLExpress伺服器。

附加至 localhost\SQLExpress Server

圖 1:附加至 localhost\SQLExpress 伺服器

聯機到伺服器之後,Management Studio 會顯示伺服器,並具有資料庫、安全性等子資料夾。 以滑鼠右鍵按兩下 [資料庫] 資料夾,然後選擇 [附加] 選項。 這會顯示 [附加資料庫] 對話框, (請參閱圖 2) 。 按兩下 [新增] 按鈕,然後選取 NORTHWND.MDF Web 應用程式資料夾中 App_Data 的資料庫資料夾。

附加 NORTHWND。App_Data資料夾中的 MDF 資料庫

圖 2:從App_Data資料夾附加NORTHWND.MDF資料庫 (按下即可檢視完整大小的影像)

這會將資料庫新增至 [資料庫] 資料夾。 資料庫名稱可能是資料庫檔案的完整路徑,或前面加上 GUID 的完整路徑。 若要避免在使用 aspnet_regsql.exe 命令行工具時必須輸入這個冗長的資料庫名稱,請以滑鼠右鍵按下剛附加的資料庫並選擇 [重新命名],將資料庫重新命名為更易記的名稱。 我已將資料庫重新命名為 DataTutorials 。

將附加資料庫重新命名為更多 Human-Friendly 名稱

圖 3:將附加資料庫重新命名為更多 Human-Friendly 名稱

步驟 3:將輪詢基礎結構新增至 Northwind 資料庫

既然我們已從 App_Data 資料夾附加NORTHWND.MDF資料庫,我們就可以新增輪詢基礎結構。 假設您已將資料庫重新命名為 DataTutorials,請執行下列四個命令:

aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -ed
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Products -et
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Categories -et
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Suppliers -et

執行這四個命令之後,以滑鼠右鍵按兩下Management Studio 中的資料庫名稱,移至 [工作] 子功能表,然後選擇 [中斷連結]。 然後關閉 Management Studio,然後重新開啟 Visual Studio。

Visual Studio 重新開啟之後,請透過 [伺服器總管] 鑽研資料庫。 請注意新的資料表 (AspNet_SqlCacheTablesForChangeNotification) 、新的預存程式和、 CategoriesSuppliers 資料表上的Products觸發程式。

資料庫現在包含必要的輪詢基礎結構

圖 4:資料庫現在包含必要的輪詢基礎結構

步驟 4:設定輪詢服務

在資料庫中建立所需的數據表、觸髮程式和預存程式之後,最後一個步驟是設定輪詢服務, Web.config 方法是指定要使用的資料庫,並以毫秒為單位輪詢頻率來完成。 下列標記會每秒輪詢 Northwind 資料庫一次。

<?xml version="1.0"?>
<configuration>
   <connectionStrings>
      <add name="NORTHWNDConnectionString" connectionString=
          "Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
           Integrated Security=True;User Instance=True" 
           providerName="System.Data.SqlClient"/>
   </connectionStrings>
   <system.web>
      ...
      <!-- Configure the polling service used for SQL cache dependencies -->
      <caching>
         <sqlCacheDependency enabled="true" pollTime="1000" >
            <databases>
               <add name="NorthwindDB" 
                    connectionStringName="NORTHWNDConnectionString" />
            </databases>
         </sqlCacheDependency>
      </caching>
   </system.web>
</configuration>

name NorthwindDB ( 元素中的<add>值 ) 將人類可讀取的名稱與特定資料庫產生關聯。 使用 SQL 快取相依性時,我們必須參考這裡定義的資料庫名稱,以及快取數據所依據的數據表。 我們將瞭解如何使用 SqlCacheDependency 類別,以程序設計方式將 SQL 快取相依性與步驟 6 中的快取數據產生關聯。

建立 SQL 快取相依性之後,輪詢系統會每隔pollTime毫秒連接到元素中<databases>定義的資料庫,並執行AspNet_SqlCachePollingStoredProcedure預存程式。 這個預存程式 -這是使用aspnet_regsql.exe命令行工具在步驟 3 中加回的 , 會tableName傳回 中每個記錄的 AspNet_SqlCacheTablesForChangeNotificationchangeId 值。 過期的 SQL 快取相依性會從快取收回。

pollTime 設定會在效能和數據過時之間帶來取捨。 較小的 pollTime 值會增加對資料庫的要求數目,但更快速地從快取收回過時的數據。 較大的 pollTime 值會減少資料庫要求數目,但會增加後端數據變更和收回相關快取專案之間的延遲。 幸運的是,資料庫要求正在執行簡單的預存程式,只從簡單輕量型數據表傳回幾個數據列。 但是,請試驗不同的 pollTime 值,以找出應用程式數據庫存取和數據過時之間的理想平衡。 允許的最小值 pollTime 是 500。

注意

上述範例會在 元素中提供單pollTime一值,但您可以選擇性地在 元素中<add>指定pollTime值。<sqlCacheDependency> 如果您有多個資料庫指定,而且想要自定義每個資料庫的輪詢頻率,這會很有用。

步驟 5:以宣告方式使用 SQL 快取相依性

在步驟 1 到 4 中,我們探討如何設定必要的資料庫基礎結構和設定輪詢系統。 有了此基礎結構,我們現在可以使用程序設計或宣告式技術,將專案新增至具有相關聯 SQL 快取相依性的數據快取。 在此步驟中,我們將探討如何以宣告方式使用 SQL 快取相依性。 在步驟 6 中,我們將探討程序設計方法。

使用 ObjectDataSource 快取數據教學課程探索了 ObjectDataSource 的宣告式快取功能。 只要將 EnableCaching 屬性設定為 True ,並將 CacheDuration 屬性設定為某個時間間隔,ObjectDataSource 就會針對指定的間隔自動快取從其基礎對象傳回的數據。 ObjectDataSource 也可以使用一或多個 SQL 快取相依性。

若要示範如何以宣告方式使用 SQL 快取相依性,請開啟SqlCacheDependencies.aspx資料夾中的頁面Caching,並將 GridView 從 [工具箱] 拖曳至 Designer。 將 GridView 設為 IDProductsDeclarative ,並從其智慧標記中選擇將其系結至名為 ProductsDataSourceDeclarative的新 ObjectDataSource。

建立名為 ProductsDataSource 的新 ObjectDataSourceDeclarative

圖 5:建立名為 ProductsDataSourceDeclarative 的新 ObjectDataSource (按兩下即可檢視大小完整的映像)

將 ObjectDataSource 設定為使用 類別, ProductsBLL 並將 SELECT 索引標籤標的下拉式清單設定為 GetProducts()。 在 [更新] 索引標籤中 UpdateProduct ,選擇具有三個輸入參數的多載 - productNameunitPriceproductID。 將下拉式清單設定為 [INSERT] 和 [DELETE] 索引標籤中的 [無]) (。

使用 UpdateProduct 多載搭配三個輸入參數

圖 6:使用 UpdateProduct 多載搭配三個輸入參數 (按兩下即可檢視大小完整的映像)

將 [Drop-Down 列表] 設定為 ([INSERT] 和 [DELETE] 索引標籤的 [無) ]

圖 7:將 [Drop-Down 列表] 設定為 ([插入] 和 [刪除] 索引卷標的 [無) ] (按兩下即可檢視大小完整的影像)

完成 [設定數據源精靈] 之後,Visual Studio 會在 GridView 中為每個數據字段建立 BoundFields 和 CheckBoxFields。 拿掉所有欄位,但 ProductNameCategoryName、 和 UnitPrice,並視需要格式化這些欄位。 從 GridView 的智慧標記中,核取 [啟用分頁]、[啟用排序] 和 [啟用編輯] 複選框。 Visual Studio 會將 ObjectDataSource s OldValuesParameterFormatString 屬性設定為 original_{0}。 為了讓 GridView 的編輯功能正常運作,請完全從宣告式語法中移除此屬性,或將其設定回其預設值 。 {0}

最後,在 GridView 上方新增標籤 Web 控件,並將其 屬性設定為 ODSEvents ,並將其 EnableViewState 屬性設定IDFalse。 進行這些變更之後,頁面的宣告式標記看起來應該類似下列內容。 請注意,我已對 GridView 欄位進行一些美觀自定義,這些欄位不需要示範 SQL 快取相依性功能。

<asp:Label ID="ODSEvents" runat="server" EnableViewState="False" />
<asp:GridView ID="ProductsDeclarative" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSourceDeclarative" 
    AllowPaging="True" AllowSorting="True">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <EditItemTemplate>
                <asp:TextBox ID="ProductName" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                    ControlToValidate="ProductName" Display="Dynamic" 
                    ErrorMessage="You must provide a name for the product." 
                    SetFocusOnError="True"
                    runat="server">*</asp:RequiredFieldValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <EditItemTemplate>
                $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                    Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="UnitPrice"
                    ErrorMessage="You must enter a valid currency value with 
                        no currency symbols. Also, the value must be greater than 
                        or equal to zero."
                    Operator="GreaterThanEqual" SetFocusOnError="True" 
                    Type="Currency" Display="Dynamic" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSourceDeclarative" runat="server" 
    SelectMethod="GetProducts" TypeName="ProductsBLL" 
    UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

接下來,建立 ObjectDataSource s Selecting 事件的事件處理程式,並在其中新增下列程式代碼:

Protected Sub ProductsDataSourceDeclarative_Selecting _
    (sender As Object, e As ObjectDataSourceSelectingEventArgs) _
    Handles ProductsDataSourceDeclarative.Selecting
    ODSEvents.Text = "-- Selecting event fired"
End Sub

回想一下,只有在從其基礎物件擷取數據時,才會引發 ObjectDataSource s Selecting 事件。 如果 ObjectDataSource 從自己的快取存取數據,就不會引發此事件。

現在,請透過瀏覽器瀏覽此頁面。 由於我們尚未實作任何快取,因此每次頁面、排序或編輯方格時,頁面應該會顯示文字「選取引發的事件,如圖 8 所示。

每次 GridView 分頁、編輯或排序時,都會引發 ObjectDataSource 的 Select 事件

圖 8:每次 GridView 已分頁、編輯或 (排序時,都會引發 ObjectDataSource s Selecting 事件 ,按兩下即可檢視大小完整的影像)

如我們在 使用 ObjectDataSource 教學課程快取數據 中所見,將 屬性設定 EnableCachingTrue 會導致 ObjectDataSource 在其 屬性所指定的持續時間內快取其 CacheDuration 數據。 ObjectDataSource 也有 SqlCacheDependency 屬性,它會使用 模式,將一或多個 SQL 快取相依性新增至快取的數據:

databaseName1:tableName1;databaseName2:tableName2;...

其中 databaseName 是 中 專案Web.config之 屬性<add>中指定的name資料庫名稱,而 tableName 是資料庫數據表的名稱。 例如,若要建立 ObjectDataSource,根據 Northwind Products 數據表的 SQL 快取相依性無限期地快取數據,請將 ObjectDataSource s EnableCaching 屬性設定為 True ,並將其 SqlCacheDependency 屬性設定為 NorthwindDB:Products 。

注意

您可以使用 SQL 快取相依性和以時間為基礎的到期,方法是將 設定EnableCachingTrue為 、CacheDuration設定為時間間隔,以及SqlCacheDependency資料庫和數據表名稱, (s) 。 當到達以時間為基礎的到期或輪詢系統注意到基礎資料庫數據已變更時,ObjectDataSource 將會收回其數據,無論何時先發生。

中的 SqlCacheDependencies.aspx GridView 會顯示來自兩個數據表的數據, Products 而且 Categories (產品 CategoryName 欄位是透過 JOIN) 上的 Categories 擷取。 因此,我們想要指定兩個 SQL 快取相依性:NorthwindDB:Products;NorthwindDB:Categories 。

設定 ObjectDataSource 以支援使用產品與類別的 SQL 快取相依性進行快取

圖 9:設定 ObjectDataSource 以支援使用 SQL 快取相依性 Products 進行快取, (Categories按兩下即可檢視完整大小的映像)

設定 ObjectDataSource 以支援快取之後,請透過瀏覽器重新瀏覽頁面。 同樣地,[選取引發的事件] 文字應該會出現在第一頁流覽中,但應該在分頁、排序或按兩下 [編輯] 或 [取消] 按鈕時消失。 這是因為將數據載入 ObjectDataSource 快取之後,它會保留在該處,直到 ProductsCategories 資料表經過修改或透過 GridView 更新數據為止。

在分頁流覽方格並注意缺少「選取事件引發的文字」之後,請開啟新的瀏覽器視窗,並在 [編輯]、[插入] 和 [刪除] 區段中流覽至 [基本概念] 教學課程, (~/EditInsertDelete/Basics.aspx) 。 更新產品的名稱或價格。 然後,從 到第一個瀏覽器視窗,檢視不同的數據頁面、排序方格,或按兩下資料列的 [編輯] 按鈕。 這次,「選取事件應該會重新出現,因為基礎資料庫數據已修改 (請參閱圖 10) 。 如果文字未出現,請稍候片刻,然後再試一次。 請記住,輪詢服務會每隔pollTime毫秒檢查數據表的變更Products,因此基礎數據更新和快取數據收回時之間會有延遲。

修改 Products 數據表會收回快取的產品數據

圖 10:修改產品數據表會收回快取的產品數據 (按兩下即可檢視完整大小的映像)

步驟 6:以程式設計方式使用SqlCacheDependency類別

架構中的快取數據教學課程探討在架構中使用個別快取層的優點,而不是緊密結合 ObjectDataSource 的快取。 在本教學課程中,我們已建立類別 ProductsCL ,以程序設計方式使用數據快取。 若要在快取層中使用 SQL 快取相依性,請使用 類別 SqlCacheDependency

使用輪詢系統時, SqlCacheDependency 對象必須與特定資料庫和數據表組相關聯。 例如,下列程式代碼會根據 Northwind 資料庫數據表Products建立 SqlCacheDependency 物件:

Dim productsTableDependency As _
    New Caching.SqlCacheDependency("NorthwindDB", "Products")

建構函式的 SqlCacheDependency 兩個輸入參數分別是資料庫和數據表名稱。 就像使用 ObjectDataSource s SqlCacheDependency 屬性一樣,所使用的資料庫名稱與 中 Web.config專案之 屬性<add>中指定的name值相同。 數據表名稱是資料庫數據表的實際名稱。

若要將 與新增至數據快取的專案產生關聯 SqlCacheDependency ,請使用接受相依性的方法多載之 Insert 一。 下列程式代碼會無限期地將數據快取 新增至數據快取,但會將它與 SqlCacheDependency 數據表上的 Products 產生關聯。 簡單來說, 會保留在快取中,直到因為記憶體限制而收回,或因為輪詢系統偵測 Products 到數據表在快取之後已變更。

Dim productsTableDependency As _
    New Caching.SqlCacheDependency("NorthwindDB", "Products")
Cache.Insert(key, _
             value, _ 
             productsTableDependency, _
             System.Web.Caching.Cache.NoAbsoluteExpiration, _
             System.Web.Caching.Cache.NoSlidingExpiration)

快取層的 ProductsCL 類別目前會使用 60 秒的時間型到期,從 Products 數據表快取數據。 讓我們更新這個類別,讓它改用 SQL 快取相依性。 類別 ProductsCL s AddCacheItem 方法,負責將資料新增至快取,目前包含下列程式代碼:

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Make sure MasterCacheKeyArray(0) is in the cache - if not, add it
    If DataCache(MasterCacheKeyArray(0)) Is Nothing Then
        DataCache(MasterCacheKeyArray(0)) = DateTime.Now
    End If
    ' Add a CacheDependency
    Dim dependency As _
        New Caching.CacheDependency(Nothing, MasterCacheKeyArray)
    DataCache.Insert(GetCacheKey(rawKey), value, dependency, _
        DateTime.Now.AddSeconds(CacheDuration), _
        Caching.Cache.NoSlidingExpiration)
End Sub

更新此程式代碼以使用物件,而不是MasterCacheKeyArraySqlCacheDependency取相依性:

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Add the SqlCacheDependency objects for Products
    Dim productsTableDependency As New _
        Caching.SqlCacheDependency("NorthwindDB", "Products")
    DataCache.Insert(GetCacheKey(rawKey), value, productsTableDependency, _
        Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration)
End Sub

若要測試這項功能,請將 GridView 新增至現有 ProductsDeclarative GridView 下方的頁面。 將這個新的 GridView 設定 IDProductsProgrammatic ,並透過其智慧標記將它系結至名為 ProductsDataSourceProgrammatic的新 ObjectDataSource。 將 ObjectDataSource 設定為使用 ProductsCL 類別,分別將 SELECT 和 UPDATE 索引標籤中的下拉式清單設定為 GetProductsUpdateProduct

將 ObjectDataSource 設定為使用 ProductsCL 類別

圖 11:將 ObjectDataSource 設定為使用 ProductsCL 類別 (按兩下即可檢視完整大小的映像)

從 SELECT 索引標籤 Drop-Down 清單中選取 GetProducts 方法

圖 12:從 SELECT GetProducts 索引標籤 Drop-Down 清單選取方法 (按兩下以檢視大小完整的影像)

從 [更新] 索引標籤 Drop-Down 清單中選擇 UpdateProduct 方法

圖 13:從 [更新] 索引標籤 Drop-Down 清單選擇 UpdateProduct 方法, (按兩下即可檢視大小完整的映像)

完成 [設定數據源精靈] 之後,Visual Studio 會在 GridView 中為每個數據字段建立 BoundFields 和 CheckBoxFields。 如同新增至此頁面的第一個 GridView,請移除所有欄位,但 ProductNameCategoryName、 和 UnitPrice,並視需要格式化這些欄位。 從 GridView 的智慧標記中,核取 [啟用分頁]、[啟用排序] 和 [啟用編輯] 複選框。 ProductsDataSourceDeclarative如同 ObjectDataSource,Visual Studio 會將 ObjectDataSource s OldValuesParameterFormatString 屬性設定ProductsDataSourceProgrammaticoriginal_{0}。 為了讓 GridView 的編輯功能正常運作,請將此屬性設定回 {0} (,或從宣告式語法中移除屬性指派) 。

完成這些工作之後,產生的 GridView 和 ObjectDataSource 宣告式標記看起來應該如下所示:

<asp:GridView ID="ProductsProgrammatic" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSourceProgrammatic" AllowPaging="True" 
    AllowSorting="True">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <EditItemTemplate>
                <asp:TextBox ID="ProductName" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1"  
                    ControlToValidate="ProductName" Display="Dynamic" 
                    ErrorMessage="You must provide a name for the product." 
                    SetFocusOnError="True"
                    runat="server">*</asp:RequiredFieldValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <EditItemTemplate>
                $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                    Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="UnitPrice" Display="Dynamic" 
                    ErrorMessage="You must enter a valid currency value with no 
                        currency symbols. Also, the value must be greater than 
                        or equal to zero."
                    Operator="GreaterThanEqual" SetFocusOnError="True" 
                    Type="Currency" ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSourceProgrammatic" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetProducts" 
    TypeName="ProductsCL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

若要測試快取層中的 SQL 快取相依性,請在 類別 s AddCacheItem 方法中ProductCL設定斷點,然後開始偵錯。 當您第一次造訪 SqlCacheDependencies.aspx時,應該叫用斷點,因為第一次要求數據並放入快取中。 接下來,移至 GridView 中的另一個頁面,或排序其中一個數據行。 這會導致 GridView 重新查詢其數據,但應該在快取中找到數據,因為 Products 資料庫數據表尚未修改。 如果在快取中重複找不到數據,請確定計算機上有足夠的可用記憶體,然後再試一次。

在分頁瀏覽 GridView 的幾個頁面之後,請開啟第二個瀏覽器視窗,然後流覽至 [編輯]、[插入] 和 [刪除] 區段中的 [基本概念] 教學課程, () ~/EditInsertDelete/Basics.aspx 。 從 Products 資料表更新記錄,然後從第一個瀏覽器視窗檢視新的頁面,或按兩下其中一個排序標頭。

在此案例中,您會看到下列兩件事之一:將會叫用斷點,指出快取的數據因為資料庫中的變更而遭到收回;或者,不會叫用斷點,這表示 SqlCacheDependencies.aspx 現在顯示過時的數據。 如果斷點未叫用,可能是因為輪詢服務尚未在數據變更后引發。 請記住,輪詢服務會每隔pollTime毫秒檢查數據表的變更Products,因此基礎數據更新和快取數據收回時之間會有延遲。

注意

透過中的 SqlCacheDependencies.aspxGridView 編輯其中一個產品時,較可能會顯示此延遲。 在 架構教學課程的快取數據中 ,我們新增 MasterCacheKeyArray 了快取相依性,以確保透過 ProductsCL 類別 s UpdateProduct 方法編輯的數據已從快取收回。 不過,我們稍早在此步驟中修改 AddCacheItem 方法時,會取代此快取相依性,因此 ProductsCL 類別會繼續顯示快取的數據,直到輪詢系統記下數據表的變更 Products 為止。 我們將瞭解如何在步驟 7 中重新引進 MasterCacheKeyArray 快取相依性。

步驟 7:將多個相依性與快取專案產生關聯

回想一下,快 MasterCacheKeyArray 取相依性是用來確保 當快 取內任何相關聯的單一專案更新時,會從快取收回所有產品相關數據。 例如, GetProductsByCategoryID(categoryID) 方法會 ProductsDataTables 快取每個唯一 categoryID 值的實例。 如果收回其中一個物件,快 MasterCacheKeyArray 取相依性可確保也會移除其他物件。 如果沒有此快取相依性,當快取的數據遭到修改時,可能會有其他快取的產品數據已過期的可能性。 因此,請務必在使用 SQL 快取相依性時維護 MasterCacheKeyArray 快取相依性。 不過,數據快取的 Insert 方法只允許單一相依性物件。

此外,使用 SQL 快取相依性時,可能需要將多個資料庫數據表關聯為相依性。 例如, ProductsDataTable 類別中 ProductsCL 快取的 包含每個產品的類別和供應商名稱,但 AddCacheItem 方法只會使用 相依性 Products。 在此情況下,如果使用者更新類別或供應商的名稱,則快取的產品數據會保留在快取中,並過期。 因此,我們想要讓快取的產品數據不只 Products 相依於數據表,也取決於 CategoriesSuppliers 數據表。

類別AggregateCacheDependency提供將多個相依性與快取專案產生關聯的方法。 從建立 AggregateCacheDependency 實例開始。 接下來,使用 AggregateCacheDependency s Add 方法新增一組相依性。 在之後將專案插入數據快取時,請傳入 AggregateCacheDependency 實例。 當 任何 實例的相 AggregateCacheDependency 依性變更時,將會收回快取的專案。

以下顯示 類別 s AddCacheItem 方法的ProductsCL更新程式代碼。 方法會建立快MasterCacheKeyArray取相依性,以及 SqlCacheDependencyCategoriesSuppliers 數據表的物件Products。 這些全都會合併成一個名為 AggregateCacheDependencyaggregateDependencies的物件,然後傳遞至 Insert 方法。

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Make sure MasterCacheKeyArray(0) is in the cache - if not, add it.
    If DataCache(MasterCacheKeyArray(0)) Is Nothing Then
        DataCache(MasterCacheKeyArray(0)) = DateTime.Now
    End If
    'Create the CacheDependency
    Dim masterCacheKeyDependency As _
        New Caching.CacheDependency(Nothing, MasterCacheKeyArray)
    ' Add the SqlCacheDependency objects for Products, Categories, and Suppliers
    Dim productsTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Products")
    Dim categoriesTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Categories")
    Dim suppliersTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Suppliers")
    ' Create an AggregateCacheDependency
    Dim aggregateDependencies As New Caching.AggregateCacheDependency()
    aggregateDependencies.Add(masterCacheKeyDependency, productsTableDependency, _
        categoriesTableDependency, suppliersTableDependency)
    DataCache.Insert(GetCacheKey(rawKey), value, aggregateDependencies, _
        Caching.Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration)
End Sub

測試這個新的程序代碼。現在對、 CategoriesSuppliers 數據表所做的Products變更會導致收回快取的數據。 此外, ProductsCL 透過 GridView 編輯產品時所呼叫的類別 s UpdateProduct 方法會收回 MasterCacheKeyArray 快取相依性,這會導致 ProductsDataTable 快取被收回,並在下一個要求上重新擷取數據。

注意

SQL 快取相依性也可以與 輸出快取搭配使用。 如需此功能的示範,請參閱:搭配使用 ASP.NET 輸出快取搭配 SQL Server

摘要

快取資料庫數據時,數據最好會保留在快取中,直到資料庫修改為止。 使用 ASP.NET 2.0 時,可以在宣告式和程序設計案例中建立及使用 SQL 快取相依性。 這種方法的其中一項挑戰是在修改數據時進行探索。 Microsoft SQL Server 2005 的完整版本提供通知功能,可在查詢結果變更時警示應用程式。 針對 SQL Server 2005 和舊版的 Express 版本 SQL Server,必須改用輪詢系統。 幸運的是,設定必要的輪詢基礎結構相當簡單。

快樂的程序設計!

深入閱讀

如需本教學課程中討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET

特別感謝

本教學課程系列是由許多實用的檢閱者檢閱。 本教學課程的首席檢閱者是 Marko Rangel、Teresa Murphy 和一個入口網站 Giesenow。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。