Поделиться через


Использование зависимостей кэша SQL (VB)

Скотт Митчелл

Скачать в формате PDF

Самая простая стратегия кэширования — это позволить кэшированным данным истечь после определенного периода времени. Но этот простой подход означает, что кэшированные данные не поддерживают связь со своим базовым источником данных, что приводит к устаревшим данным, хранящимся слишком долго, или к актуальным данным, срок действия которых истекает слишком рано. Лучший подход — использовать класс SqlCacheDependency, чтобы данные сохранялись в кэше, пока не были изменены базовые данные в базе данных SQL. В этом руководстве показано, как это сделать.

Введение

Методы кэширования, рассмотренные в кэшировании данных с помощью ObjectDataSource и кэширования данных в учебниках по архитектуре , использовали срок действия на основе времени для вытеснения данных из кэша после указанного периода. Этот подход является самым простым способом балансировки производительности кэширования по отношению к устаревшим данным. Выбрав срок действия x секунд, разработчик страницы признает преимущества кэширования в течение только x секунд, но может быть спокойна, что ее данные никогда не будут устаревшими не более x секунд. Конечно, для статических данных x можно расширить до времени существования веб-приложения, как было рассмотрено в руководстве по кэшированию данных при запуске приложения .

При кэшировании данных базы данных срок действия на основе времени часто выбирается для простоты использования, но часто является неадекватным решением. В идеале данные базы данных останутся в кэше до тех пор, пока исходные данные не будут изменены в базе данных; только тогда кэш будет вытеснен. Этот подход позволяет максимально повысить производительность кэширования и свести к минимуму продолжительность устаревших данных. Однако для того, чтобы воспользоваться этими преимуществами, необходимо иметь некоторую систему, которая знает, когда базовые данные базы данных были изменены и вытеснены соответствующие элементы из кэша. До ASP.NET 2.0 разработчики страниц несут ответственность за реализацию этой системы.

ASP.NET 2.0 предоставляет SqlCacheDependency класс и необходимую инфраструктуру, чтобы определить, когда произошло изменение в базе данных, чтобы соответствующие кэшированные элементы можно было вытеснять. Существует два метода определения того, когда изменены базовые данные: уведомление и опрос. Обсудив различия между уведомлениями и опросами, мы создадим инфраструктуру, необходимую для поддержки опроса, а затем рассмотрим, как использовать SqlCacheDependency класс в декларативных и программных сценариях.

Общие сведения о уведомлениях и опросах

Существует два метода, которые можно использовать для определения того, когда данные в базе данных были изменены: уведомление и опрос. При уведомлении база данных автоматически оповещает среду выполнения ASP.NET, когда результаты определенного запроса были изменены с момента последнего выполнения запроса, в то время как кэшированные элементы, связанные с запросом, вытесняются. При опросе сервер базы данных сохраняет сведения о времени последнего обновления определенных таблиц. Среда выполнения ASP.NET периодически опрашивает базу данных, чтобы проверить, какие таблицы изменились, так как они были введены в кэш. Таблицы, данные в которых были изменены, приводят к удалению связанных элементов кэша.

Параметр уведомления требует меньшей настройки, чем опрос и более детализирован, так как он отслеживает изменения на уровне запроса, а не на уровне таблицы. К сожалению, уведомления доступны только в полных выпусках Microsoft SQL Server 2005 (т. е. выпусков, отличных от Express). Однако параметр опроса можно использовать для всех версий Microsoft SQL Server с 7.0 по 2005 год. Так как в этих руководствах используется выпуск SQL Server 2005 Express, мы сосредоточимся на настройке и использовании параметра опроса. Ознакомьтесь с разделом "Дополнительное чтение" в конце этого руководства, чтобы получить дополнительные ресурсы в возможностях уведомлений SQL Server 2005.

При опросе база данных должна быть настроена для включения таблицы с именем AspNet_SqlCacheTablesForChangeNotification трех столбцов — tableNamenotificationCreatedи changeId. Эта таблица содержит строку для каждой таблицы с данными, которые могут потребоваться использовать в зависимости кэша SQL в веб-приложении. Столбец tableName указывает имя таблицы, указывая notificationCreated дату и время добавления строки в таблицу. Столбец changeId имеет тип int и имеет начальное значение 0. Его значение увеличивается с каждым изменением таблицы.

AspNet_SqlCacheTablesForChangeNotification Помимо таблицы, в базе данных также необходимо включить триггеры для каждой таблицы, которая может фигурировать в зависимости SQL-кеш. Эти триггеры выполняются всякий раз, когда строка вставляется, обновляется или удаляется, и увеличивают значение таблицы changeId в AspNet_SqlCacheTablesForChangeNotification.

Среда выполнения ASP.NET отслеживает текущую changeId для таблицы при кэшировании данных с помощью SqlCacheDependency объекта. База данных периодически проверяется и все SqlCacheDependency объекты, которые changeId отличаются от значения в базе данных, вытеснены, так как разное changeId значение указывает на то, что после кэширования данных произошло изменение таблицы.

Шаг 1. Изучение программы для работы с команднойaspnet_regsql.exeстрокой

При подходе к опросу база данных должна быть настроена, чтобы содержать инфраструктуру, описанную выше: предопределенную таблицу (AspNet_SqlCacheTablesForChangeNotification), горстку хранимых процедур и триггеры для каждой из таблиц, которые могут использоваться в зависимостях кэша 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_securityadmin и db_ddladmin.

Например, чтобы добавить инфраструктуру для опроса в базу данных Microsoft SQL Server с именем pubs на сервере базы данных с именем ScottsServer с помощью проверки подлинности Windows, перейдите в соответствующий каталог и в командной строке введите:

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 и titles в базе данных pubs на ScottsServer, используйте:

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

Для этого руководства добавьте триггеры в таблицы Products, Categories, и Suppliers. Мы рассмотрим конкретный синтаксис командной строки на шаге 3.

Шаг 2. Ссылка на базу данных Microsoft SQL Server 2005 Express Edition вApp_Data

В программе aspnet_regsql.exe командной строки требуется имя базы данных и сервера, чтобы добавить необходимую инфраструктуру опроса. Но что такое база данных и имя сервера для базы данных Microsoft SQL Server 2005 Express, которая находится в папке App_Data ? Вместо того чтобы выяснять, как называются базы данных и серверы, я обнаружил, что самый простой подход заключается в подключении базы данных к экземпляру 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 и выберите подключение к localhost\SQLExpress серверу с помощью проверки подлинности Windows.

Присоединение к localhost\SQLExpress Server

Рис. 1. Подключение к localhost\SQLExpress серверу

После подключения к серверу Management Studio отобразит сервер и вложенные папки для баз данных, безопасности и т. д. Щелкните правой кнопкой мыши папку "Базы данных" и выберите параметр "Подключить". Откроется диалоговое окно "Присоединение баз данных" (см. рис. 2). Нажмите кнопку "Добавить" и выберите NORTHWND.MDF папку базы данных в папке веб-приложения App_Data .

Прикрепить базу данных NORTHWND.MDF из папки App_Data

Рис. 2. Присоединение NORTHWND.MDF базы данных из App_Data папки (щелкните, чтобы просмотреть изображение полного размера)

При этом база данных будет добавлена в папку "Базы данных". Имя базы данных может быть полным путем к файлу базы данных или полный путь, заданный с помощью GUID. Чтобы избежать необходимости вводить это длинное имя базы данных при использовании средства командной строки aspnet_regsql.exe, переименуйте базу данных в более понятное для человека имя, щелкнув правой кнопкой мыши базу данных, только что подключенную и выбрав "Переименовать". Я переименовал базу данных в DataTutorials.

Переименуйте присоединенную базу данных в более подходящее имя Human-Friendly

Рис. 3. Переименуйте присоединенную базу данных в более подходящее Human-Friendly имя

Шаг 3. Добавление инфраструктуры опроса в базу данных Northwind

Теперь, когда мы подключили NORTHWND.MDF базу данных из App_Data папки, мы готовы добавить инфраструктуру опроса. Если вы переименовали базу данных в 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), новые хранимые процедуры и триггеры на таблицах Products, Categories и Suppliers.

База данных теперь включает необходимую инфраструктуру опроса

Рис. 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 в элементе <add> (NorthwindDB) связывает имя, доступное для чтения человеком, с определенной базой данных. При работе с зависимостями кэша SQL необходимо ссылаться на имя базы данных, определенное здесь, а также таблицу, на которую основаны кэшированные данные. Мы посмотрим, как использовать SqlCacheDependency класс для программного связывания зависимостей кэша SQL с кэшируемыми данными на шаге 6.

После того как зависимость кэша SQL будет установлена, система опроса будет подключаться к базам данных, определённым в <databases> элементах, каждые pollTime миллисекунд и выполнит хранимую процедуру AspNet_SqlCachePollingStoredProcedure. Эта хранимая процедура, которая была добавлена обратно на шаге 3 с помощью средства командной строки aspnet_regsql.exe, возвращает значения tableName и changeId для каждой записи в AspNet_SqlCacheTablesForChangeNotification. Устаревшие зависимости кэша SQL вытеснены из кэша.

Этот pollTime параметр представляет компромисс между производительностью и устаревшими данными. Небольшое pollTime значение увеличивает количество запросов к базе данных, но быстрее вытесняет устаревшие данные из кэша. Большее значение pollTime уменьшает количество запросов к базе данных, но увеличивает задержку между изменениями данных бэкенда и вытеснением связанных элементов кэша. К счастью, запрос базы данных выполняет простую хранимую процедуру, которая возвращает всего несколько строк из простой упрощенной таблицы. Но экспериментируйте с различными значениями pollTime, чтобы найти идеальный баланс между доступом к базе данных и устареванием данных. Наименьшее pollTime допустимое значение — 500.

Замечание

Приведенный выше пример предоставляет одно pollTime значение в <sqlCacheDependency> элементе, но при необходимости можно указать pollTime значение в элементе <add> . Это полезно, если у вас несколько баз данных и требуется настроить частоту опроса для каждой базы данных.

Шаг 5. Декларативная работа с зависимостями кэша SQL

В шагах 1–4 мы рассмотрели, как настроить необходимую инфраструктуру базы данных и настроить систему опроса. Благодаря этой инфраструктуре теперь можно добавить элементы в кэш данных с связанной зависимостью кэша SQL с помощью программных или декларативных методов. На этом шаге мы рассмотрим, как декларативно работать с зависимостями кэша SQL. На шаге 6 мы рассмотрим программный подход.

В руководстве по кэшированию данных с помощью ObjectDataSource рассматриваются декларативные возможности кэширования объекта ObjectDataSource. Просто установив свойство EnableCaching на True и свойство CacheDuration на некоторый временной интервал, ObjectDataSource автоматически кэширует данные, возвращаемые из его базового объекта, на указанный интервал. ObjectDataSource также может использовать одну или несколько зависимостей кэша SQL.

Чтобы продемонстрировать декларативное использование зависимостей кэша SQL, откройте SqlCacheDependencies.aspx страницу в папке Caching и перетащите элемент GridView из панели элементов на холст конструктора. Задайте для GridView значение IDProductsDeclarative и из смарт-тега выберите для привязки его к новому объекту ObjectDataSource с именем ProductsDataSourceDeclarative.

Создание нового объекта ObjectDataSource С именем ProductsDataSourceDeclarative

Рис. 5. Создание объекта ObjectDataSource С именем ProductsDataSourceDeclarative (щелкните, чтобы просмотреть изображение полного размера)

Настройте ObjectDataSource для использования класса ProductsBLL и задайте параметр "выпадающий список" на вкладке SELECT в GetProducts(). На вкладке UPDATE выберите перегрузку UpdateProduct с тремя входными параметрами — productName, unitPrice и productID. Задайте раскрывающимся спискам значение (Нет) на вкладках INSERT и DELETE.

Используйте перегруженную функцию UpdateProduct с тремя входными параметрами

Рис. 6. Используйте перегрузку UpdateProduct с тремя входными параметрами (щелкните, чтобы просмотреть изображение в полном размере)

Задайте значение (нет) для списка Drop-Down на вкладках INSERT и DELETE.

Рис. 7: Установите для вкладок INSERT и DELETE список Drop-Down в значение (нет) (щелкните, чтобы просмотреть изображение полного размера)

После завершения работы мастера настройки источника данных Visual Studio создаст BoundFields и CheckBoxFields в GridView для каждого поля данных. Удалите все поля, кроме ProductName, CategoryName, и UnitPrice, и отформатируйте эти поля по вашему усмотрению. В смарт-теге GridView установите флажки "Включить разбиение по страницам", "Включить сортировку" и "Включить редактирование". Visual Studio присвоит свойству OldValuesParameterFormatStringObjectDataSource значение original_{0} . Чтобы функция редактирования GridView работала правильно, удалите это свойство полностью из декларативного синтаксиса или присвойте ему значение по умолчанию {0}.

Наконец, добавьте веб-элемент управления Label над GridView и задайте значение ID для его свойства ODSEvents, а значение EnableViewState для свойства False. После внесения этих изменений декларативная разметка страницы должна выглядеть следующим образом. Обратите внимание, что я сделал ряд эстетических настроек в поля 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 Selecting и добавьте в него следующий код:

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

Помните, что событие ObjectDataSource Selecting запускается только при получении данных из базового объекта. Если ОбъектDataSource обращается к данным из собственного кэша, это событие не запускается.

Теперь посетите эту страницу через браузер. Так как мы еще не реализовали кэширование, каждый раз, когда вы переходите по страницам, сортируете или редактируете сетку, страница должна отображать текст: "Событие выбора было сработано", как показано на рисунке 8.

Событие Selecting объекта ObjectDataSource срабатывает каждый раз, когда GridView перемещается по страницам, редактируется или сортируется.

Рис. 8. Событие ObjectDataSource Selecting запускается при каждом запуске GridView, редактировании или сортировке (щелкните, чтобы просмотреть изображение полного размера)

Как мы видели в учебнике по кэшированию данных с помощью ObjectDataSource, установка свойства EnableCaching в значение True приводит к кэшированию данных в ObjectDataSource на период, определяемый его свойством CacheDuration. ObjectDataSource также имеет SqlCacheDependency свойство, которое добавляет одну или несколько зависимостей SQL-кэша в данные, сохраненные в кэше, используя шаблон:

databaseName1:tableName1;databaseName2:tableName2;...

Где databaseName — это имя базы данных, как указано в name атрибуте <add> элемента в Web.config, а tableName — имя таблицы базы данных. Например, чтобы создать источник данных ObjectDataSource, который кэширует данные на неопределенный срок, базирующийся на зависимости кэша SQL от таблицы NorthwindProducts, установите для свойства ObjectDataSource EnableCaching значение True и его свойство SqlCacheDependency на NorthwindDB:Products.

Замечание

Зависимость кэша SQL и истечение срока действия на основе времени можно использовать, установив на EnableCaching, True на временной интервал, а CacheDuration на имя базы данных и таблицы. ObjectDataSource удалит свои данные, когда срок действия на основе времени истек, или когда система мониторинга определяет, что базовые данные базы данных изменились, в зависимости от того, что произойдёт первым.

GridView в SqlCacheDependencies.aspx отображает данные из двух таблиц — Products и Categories (поле CategoryName продукта извлекается посредством JOIN на Categories). Поэтому мы хотим указать две зависимости кэша SQL: NorthwindDB:Products; NorthwindDB:Categories .

Настройка ObjectDataSource для поддержки кэширования с помощью зависимостей кэша SQL для продуктов и категорий

Рис. 9. Настройка ObjectDataSource для поддержки кэширования с помощью зависимостей данных SQL Products и Categories (Нажмите, чтобы увеличить изображение)

После настройки ObjectDataSource для поддержки кэширования просмотрите страницу через браузер. Опять же, текст "Событие 'Выбор' срабатывает" должен отображаться при первом посещении страницы, но должен исчезнуть при переходе по страницам, сортировке или нажатии кнопок "Изменить" или "Отмена". Это связано с тем, что после загрузки данных в кэш ObjectDataSource он остается там, пока таблицы не будут изменены или данные не обновятся с помощью GridView.

После просмотра сетки и заметив отсутствие текста "Появляется текст о выборе события", откройте новое окно браузера и перейдите к руководству по основам в разделе "Редактирование, вставка и удаление" (~/EditInsertDelete/Basics.aspx). Обновите имя или цену продукта. Затем в первом окне браузера просмотрите другую страницу данных, отсортируйте сетку или нажмите кнопку "Изменить строку". На этот раз событие 'Selecting event fired' должно вновь появиться, так как данные базы данных были изменены (см. рис. 10). Если текст не отображается, подождите несколько минут и повторите попытку. Помните, что служба опроса проверяет наличие изменений в Products таблице каждые pollTime миллисекунды, поэтому между обновлением базовых данных и при вытеснения кэшированных данных происходит задержка.

Изменение таблицы продуктов вытесняет кэшированные данные продукта

Рис. 10. Изменение таблицы продуктов вытесняет кэшированные данные продукта (щелкните, чтобы просмотреть изображение полного размера)

Шаг 6. Программная работа с классомSqlCacheDependency

Руководство Кэширование данных в архитектуре рассмотрело преимущества использования отдельного слоя кэширования в архитектуре по сравнению с тесной связкой кэширования с ObjectDataSource. В этом руководстве мы создали ProductsCL класс для демонстрации программной работы с кэшем данных. Чтобы использовать зависимости кэша SQL в уровне кэширования, используйте SqlCacheDependency класс.

С системой SqlCacheDependency опроса объект должен быть связан с определенной парой базы данных и таблицы. Следующий код, например, создает SqlCacheDependency объект на основе таблицы базы данных Products Northwind:

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

Два входных параметра SqlCacheDependency конструктора — это имена базы данных и таблиц соответственно. Как и у свойства SqlCacheDependency ObjectDataSource, используемое имя базы данных такое же, как значение, указанное в атрибуте name элемента <add> в Web.config. Имя таблицы — это фактическое имя таблицы базы данных.

Чтобы связать 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 в настоящее время кэширует данные из таблицы Products с временем жизни 60 секунд. Давайте обновим этот класс таким образом, чтобы он использовал зависимости кэша SQL. Метод ProductsCL класса 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

Обновите этот код, чтобы использовать SqlCacheDependency объект вместо зависимости кэша MasterCacheKeyArray :

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 ID значение ProductsProgrammatic, и с помощью смарт-тега привяжите его к новому объекту ObjectDataSource с именем ProductsDataSourceProgrammatic. Настройте ObjectDataSource для использования класса ProductsCL, выбрав GetProducts и UpdateProduct в раскрывающихся списках на вкладках SELECT и UPDATE соответственно.

Настройка ObjectDataSource для использования класса ProductsCL

Рис. 11. Настройка ObjectDataSource для использования ProductsCL класса (щелкните, чтобы просмотреть изображение полного размера)

Выберите метод GetProducts из списка Drop-Down вкладки SELECT

Рис. 12. Выбор GetProducts метода из списка Drop-Down вкладки SELECT (щелкните, чтобы просмотреть изображение полного размера)

Выберите метод UpdateProduct в списке Drop-Down вкладки UPDATE

Рис. 13. Выберите метод UpdateProduct из списка Drop-Down вкладки UPDATE (щелкните, чтобы просмотреть изображение полного размера)

После завершения работы мастера настройки источника данных Visual Studio создаст BoundFields и CheckBoxFields в GridView для каждого поля данных. Как и при первом добавлении GridView на эту страницу, удалите все поля, кроме ProductName, CategoryName и UnitPrice, и отформатируйте эти поля по своему усмотрению. В смарт-теге GridView установите флажки "Включить разбиение по страницам", "Включить сортировку" и "Включить редактирование". Как и в ProductsDataSourceDeclarative объекте ObjectDataSource, Visual Studio присвоит свойству ProductsDataSourceProgrammatic ObjectDataSource OldValuesParameterFormatString значение original_{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 в слое кэширования, установите точку останова в методе ProductCL класса AddCacheItem , а затем запустите отладку. При первом посещении SqlCacheDependencies.aspxточка останова должна быть достигнута, так как данные запрашиваются в первый раз и помещаются в кэш. Затем перейдите на другую страницу в GridView или сортируйте один из столбцов. Это приводит к повторному выполнению запроса данных через GridView, но данные должны находиться в кэше, так как таблица базы данных Products не была изменена. Если данные не найдены в кэше, убедитесь, что на компьютере достаточно памяти и повторите попытку.

После просмотра нескольких страниц в GridView откройте второе окно браузера и перейдите к учебнику "Основы" в разделе "Редактирование, вставка и удаление" (~/EditInsertDelete/Basics.aspx). Обновите запись из таблицы Products, а затем в первом окне браузера просмотрите новую страницу или щелкните один из заголовков сортировки.

В этом сценарии вы увидите одну из двух вещей: будет достигнута точка останова, указывающая, что кэшированные данные были вытесщены из-за изменения в базе данных; или точка останова не будет достигнута, то есть SqlCacheDependencies.aspx теперь отображает устаревшие данные. Если точка останова не достигнута, скорее всего, служба опроса еще не была запущена после изменения данных. Помните, что служба опроса проверяет наличие изменений в Products таблице каждые pollTime миллисекунды, поэтому между обновлением базовых данных и при вытеснения кэшированных данных происходит задержка.

Замечание

Эта задержка, скорее всего, появится при редактировании одного из продуктов через GridView в SqlCacheDependencies.aspx. В учебном пособии Кэширование данных в архитектуре мы добавили MasterCacheKeyArray зависимость кэша, чтобы убедиться, что данные, редактируемые с помощью метода ProductsCL в классе UpdateProduct, были вытеснены из кэша. Однако мы заменили эту зависимость кэша при изменении AddCacheItem метода ранее на этом шаге, поэтому ProductsCL класс будет продолжать отображать кэшированные данные, пока система опроса не заметит изменение таблицы Products . Мы посмотрим, как повторно ввести зависимость кэша MasterCacheKeyArray на шаге 7.

Шаг 7. Связывание нескольких зависимостей с кэшируемым элементом

Имейте в виду, что зависимость кэша используется для гарантии того, MasterCacheKeyArray чтобы все данные, связанные с товарами, удаляются из кэша при обновлении любого отдельного элемента, связанного с ними. Например, метод GetProductsByCategoryID(categoryID) кэширует экземпляры ProductsDataTables для каждого уникального значения categoryID. Если один из этих объектов вытеснен, MasterCacheKeyArray зависимость кэша гарантирует, что остальные также удаляются. Без этой зависимости кэша при изменении кэшированных данных существует вероятность того, что другие кэшированные данные продукта могут быть устаревшими. Следовательно, важно поддерживать MasterCacheKeyArray зависимость кэша при использовании зависимостей кэша SQL. Однако метод кэширования данных Insert позволяет лишь один объект зависимости.

Кроме того, при работе с зависимостями кэша SQL может потребоваться связать несколько таблиц базы данных с зависимостями. Например, ProductsDataTable кэшированный в ProductsCL классе содержит имена категорий и поставщиков для каждого продукта, но AddCacheItem метод использует только зависимость Products. В этом случае, если пользователь обновляет имя категории или поставщика, данные кэшированного продукта останутся в кэше и будут устаревшими. Поэтому мы хотим сделать кэшированные данные продукта зависящими не только от таблицы Products, но и от таблиц Categories и Suppliers.

Класс AggregateCacheDependency предоставляет средства для связывания нескольких зависимостей с элементом кэша. Начните с создания экземпляра AggregateCacheDependency . Затем добавьте набор зависимостей с помощью AggregateCacheDependency метода s Add . При последующей вставке элемента в кэш данных, передайте экземпляр AggregateCacheDependency. При изменении зависимостей любогоAggregateCacheDependency экземпляра кэшированный элемент будет удалён.

Ниже показан обновленный код для ProductsCL класса и метода AddCacheItem. Метод создает зависимость кэша MasterCacheKeyArray вместе с SqlCacheDependency объектами для таблиц Products, Categories и Suppliers. Все они объединяются в один AggregateCacheDependency объект с именем aggregateDependencies, который затем передается в 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

Проверьте этот новый код. Теперь изменения в таблицах Products, Categories или Suppliers вызывают вытеснение кэшированных данных. Кроме того, метод класса ProductsCL, который вызывается при редактировании продукта через GridView, исключает зависимость кэша UpdateProduct, что приводит к удалению кэшированных данных MasterCacheKeyArray и повторному извлечению данных при следующем запросе.

Замечание

Зависимости кэша SQL также можно использовать с кэшированием выходных данных. Демонстрация этой функции см. в статье "Использование кэширования выходных данных ASP.NET с SQL Server".

Сводка

При кэшировании данных базы данных данные в идеале останутся в кэше, пока они не будут изменены в базе данных. При использовании ASP.NET 2.0 зависимости кэша SQL можно создавать и использовать как в декларативных, так и в программных сценариях. Одна из проблем с этим подходом заключается в обнаружении изменений данных. Полные версии Microsoft SQL Server 2005 предоставляют возможности уведомлений, которые могут оповещать приложение о изменении результата запроса. Для Express Edition SQL Server 2005 и более ранних релизов SQL Server вместо другого метода следует использовать систему опроса. К счастью, настройка необходимой инфраструктуры опроса довольно проста.

Счастливое программирование!

Дальнейшее чтение

Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:

Сведения о авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.

Особое спасибо кому

Эта серия учебников была проверена многими полезными рецензентами. Ведущими рецензентами данного руководства были Марко Рейнджл, Тереса Мерфи и Хилтон Гизеноу. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.