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


Кэширование данных при запуске приложения (VB)

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

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

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

Введение

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

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

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

Замечание

Дополнительные сведения о различиях между упреждающей и реактивной загрузкой, а также списками плюсов, минусов и рекомендаций по реализации см. в разделе "Управление содержимым кэша " руководства по архитектуре кэширования для приложений .NET Framework.

Шаг 1. Определение данных для кэширования при запуске приложения

Примеры кэширования с использованием реактивной загрузки, которые мы изучили в предыдущих двух руководствах, хорошо работают с данными, которые могут периодически изменяться и не занимает непомерно долгое время для создания. Но если кэшированные данные никогда не изменяются, срок действия, используемый реактивной загрузкой, является лишним. Аналогичным образом, если данные, которые кэшируются, требуют чрезвычайно много времени для генерации, то пользователи, чьи запросы ищут пустой кэш, будут вынуждены долго ждать, пока извлекаются базовые данные. Рассмотрите возможность кэширования статических данных и данных, которые требуют исключительно длительного времени для создания при запуске приложения.

Хотя базы данных имеют множество динамических часто изменяющихся значений, большинство из них также имеют справедливый объем статических данных. Например, практически все модели данных имеют один или несколько столбцов, содержащих определенное значение из фиксированного набора вариантов. Таблица Patients базы данных может иметь PrimaryLanguage столбец, набор значений которого может быть английский, испанский, французский, русский, японский и т. д. Часто эти типы столбцов реализуются с помощью таблиц подстановки. Вместо хранения строки на английском или французском языках в Patients таблице создается вторая таблица, которая имеет, как правило, два столбца — уникальный идентификатор и строковое описание — с записью для каждого возможного значения. Столбец PrimaryLanguage в таблице Patients хранит соответствующий уникальный идентификатор в таблице поиска. На рисунке 1 основной язык пациента Джона Доу — английский, в то время как у Эда Джонсона — русский.

Таблица

Рис. 1. Таблица Languages — это таблица подстановки, используемая таблицей Patients.

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

Мы могли кэшировать Languages данные, используя те же методы реактивной загрузки, которые рассматриваются в предыдущих руководствах. Однако реактивная загрузка использует срок действия на основе времени, который не требуется для статических данных таблицы подстановки. Хотя кэширование с помощью реактивной загрузки было бы лучше, чем отсутствие кэширования, наиболее оптимальным подходом было бы заранее загрузить данные таблицы подстановки в кэш при запуске приложения.

В этом руководстве мы рассмотрим, как кэшировать данные таблицы подстановки и другие статические сведения.

Шаг 2. Изучение различных способов кэширования данных

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

При работе с классом как правило, сначала должен быть создан его экземпляр, прежде чем можно будет получить доступ к его элементам. Например, чтобы вызвать метод из одного из классов на уровне бизнес-логики, сначала необходимо создать экземпляр класса:

Dim productsAPI As New ProductsBLL()
productsAPI.SomeMethod()
productsAPI.SomeProperty = "Hello, World!"

Прежде чем вызывать SomeMethod или работать с SomeProperty, необходимо сначала создать экземпляр класса с помощью New ключевого слова. SomeMethod и SomeProperty являются частью конкретного экземпляра. Время существования этих элементов связано со временем существования связанного объекта. Статические члены, с другой стороны, являются переменными, свойствами и методами, общими для всех экземпляров класса и, следовательно, имеют время существования до тех пор, пока класс. Статические члены указываются ключевым словом Shared.

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

Application("key") = value
Dim value As Object = Application("key")

Кэш данных предоставляет гораздо более широкий API для кэширования данных, предоставляя механизмы истечения срока действия и зависимостей, приоритеты элементов кэша и т. д. С статическими элементами и состоянием приложения такие функции необходимо добавить вручную разработчиком страницы. Однако при кэшировании данных при запуске приложения в течение всего времени существования приложения преимущества кэша данных являются спорными. В этом руководстве мы рассмотрим код, который использует все три метода кэширования статических данных.

Шаг 3. КэшированиеSuppliersданных таблицы

Таблицы базы данных Northwind, реализованные на сегодняшний день, не включают в себя традиционные таблицы подстановки. Четыре DataTable, реализованные в нашей DAL, моделируют таблицы, значения которых являются нестатичными. Вместо того чтобы тратить время на добавление новой таблицы данных в DAL, а затем создавать новый класс и методы в BLL, в этом руководстве просто предположим, что данные таблицы Suppliers являются статичными. Поэтому мы можем кэшировать эти данные при запуске приложения.

Чтобы начать, создайте новый класс с именем StaticCache.cs в папке CL .

Создание класса StaticCache.vb в папке CL

Рис. 2. Создание StaticCache.vb класса в папке CL

Необходимо добавить метод, который загружает данные при запуске в соответствующее хранилище кэша, а также методы, возвращающие данные из этого кэша.

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Private Shared suppliers As Northwind.SuppliersDataTable = Nothing
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        suppliers = suppliersBLL.GetSuppliers()
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return suppliers
    End Function
End Class

Приведенный выше код использует статическую переменную-член suppliers, чтобы сохранить результаты метода класса SuppliersBLLGetSuppliers(), вызываемого из метода LoadStaticCache(). Метод LoadStaticCache() должен вызываться во время запуска приложения. После загрузки этих данных при запуске приложения любая страница, которая должна работать с данными поставщика, может вызывать StaticCache метод класса GetSuppliers() . Таким образом, вызов базы данных для получения поставщиков происходит только один раз при запуске приложения.

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

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using application state
        Dim suppliersBLL As New SuppliersBLL()
        HttpContext.Current.Application("key") = suppliers
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpContext.Current.Application("key"), _
            Northwind.SuppliersDataTable)
    End Function
End Class

В LoadStaticCache()этом случае сведения о поставщике хранятся в ключе переменной приложения. Он возвращается в качестве соответствующего типа (Northwind.SuppliersDataTable) из GetSuppliers(). Хотя состояние приложения можно получить в классах кода ASP.NET страниц с помощью Application("key"), в рамках архитектуры необходимо использовать HttpContext.Current.Application("key"), чтобы получить текущее HttpContext.

Аналогичным образом кэш данных можно использовать в качестве хранилища кэша, как показано в следующем коде:

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        HttpRuntime.Cache.Insert("key", suppliers, Nothing, _
            Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, _
            CacheItemPriority.NotRemovable, Nothing)
    End Sub
    <System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpRuntime.Cache("key"), Northwind.SuppliersDataTable)
    End Function
End Class

Чтобы добавить элемент в кэш данных без истечения срока действия, используйте значения System.Web.Caching.Cache.NoAbsoluteExpiration и System.Web.Caching.Cache.NoSlidingExpiration в качестве входных параметров. Эта конкретная перегрузка метода кэша Insert данных была выбрана таким образом, чтобы можно было указать приоритет элемента кэша. Приоритет используется для определения элементов, которые следует удалять из кэша при низком уровне доступной памяти. Здесь мы используем приоритет NotRemovable, который гарантирует, что этот элемент кэша не будет разобран.

Замечание

В этом руководстве класс StaticCache реализуется с помощью подхода использования статической переменной-члена. Код для методов кэширования данных и состояния приложения доступен в комментариях в файле класса.

Шаг 4. Выполнение кода при запуске приложения

Чтобы выполнить код при первом запуске веб-приложения, необходимо создать специальный файл с именем Global.asax. Этот файл может содержать обработчики событий для событий уровня приложения, сеанса и запроса и здесь можно добавить код, который будет выполняться при запуске приложения.

Global.asax Добавьте файл в корневой каталог веб-приложения, щелкнув правой кнопкой мыши имя проекта веб-сайта в обозревателе решений Visual Studio и выбрав "Добавить новый элемент". В диалоговом окне "Добавить новый элемент" выберите тип элемента "Глобальный класс приложения" и нажмите кнопку "Добавить".

Замечание

Если у вас уже есть файл в проекте, тип элемента "Глобальный Global.asax класс приложения" не будет указан в диалоговом окне "Добавление нового элемента".

Добавление файла Global.asax в корневой каталог веб-приложения

Рис. 3. Добавление файла в Global.asax корневой каталог веб-приложения (щелкните, чтобы просмотреть изображение полного размера)

Шаблон файла по умолчанию Global.asax включает пять методов в теге на стороне <script> сервера:

  • Application_Start выполняется при первом запуске веб-приложения
  • Application_End выполняется при завершении работы приложения
  • Application_Error выполняется всякий раз, когда необработанное исключение достигает приложения
  • Session_Start выполняется при создании нового сеанса
  • Session_End выполняется при истечении срока действия сеанса или отмене

Обработчик Application_Start событий вызывается только один раз во время жизненного цикла приложения. Приложение запускается при первом запросе ресурса ASP.NET из приложения и продолжает выполняться до перезапуска приложения, который может произойти из-за изменения содержимого папки /Bin, изменения Global.asax, изменения содержимого в папке App_Code или изменения файла Web.config, среди других причин. Дополнительные сведения о жизненном цикле приложения см. в ASP.NET обзоре жизненного цикла приложения.

Для этих учебных пособий нам нужно добавить код только в метод Application_Start, поэтому вы можете удалить остальные. Просто вызовите метод Application_Start класса StaticCache, который загрузит и кэширует информацию о поставщике LoadStaticCache().

<%@ Application Language="VB" %>
<script runat="server">
    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        StaticCache.LoadStaticCache()
    End Sub
</script>

Вот и все! При запуске приложения метод LoadStaticCache() будет извлекать сведения о поставщике из BLL и сохранять их в статической переменной (или любом хранилище кэша, которое вы использовали в конце концов в классе StaticCache). Чтобы проверить это поведение, установите точку останова в методе Application_Start и запустите приложение. Обратите внимание, что точка останова достигается при запуске приложения. Однако последующие запросы не приводят к выполнению метода Application_Start.

Используйте точку останова, чтобы убедиться в том, что выполняется обработчик событий Application_Start

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

Замечание

Если при первом запуске отладки вы не попали в точку Application_Start останова, это связано с тем, что приложение уже запущено. Принудительно перезапустите приложение, изменив файлы Global.asax или Web.config, и затем попробуйте снова. Вы можете просто добавить (или удалить) пустую строку в конце одного из этих файлов, чтобы быстро перезапустить приложение.

Шаг 5. Отображение кэшированных данных

На этом этапе StaticCache класс имеет версию данных поставщика, кэшированных при запуске приложения, к которым можно получить доступ через его GetSuppliers() метод. Для работы с данными из слоя презентации можно использовать ObjectDataSource или программным способом вызвать StaticCache метод класса GetSuppliers() в код-бихайнде класса на странице ASP.NET. Рассмотрим использование элементов управления ObjectDataSource и GridView для отображения кэшированных сведений о поставщике.

Начните с открытия AtApplicationStartup.aspx страницы в папке Caching . Перетащите GridView из панели элементов в конструктор, присвойв свойству значение IDSuppliers. Затем из смарт-тега GridView выберите создание нового объекта ObjectDataSource с именем SuppliersCachedDataSource. Настройте ObjectDataSource для использования StaticCache метода класса GetSuppliers() .

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

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

Использование метода GetSuppliers() для получения кэшированных данных поставщика

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

После завершения работы мастера Visual Studio автоматически добавит BoundFields для каждого из полей данных в SuppliersDataTable. Ваша декларативная разметка GridView и ObjectDataSource должна выглядеть следующим образом:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

На рисунке 7 показана страница при просмотре через браузер. Выходные данные те же, если бы мы извлекали данные из класса SuppliersBLL BLL, но использование класса StaticCache возвращает данные поставщика, кэшированные при запуске приложения. Для проверки этого поведения можно задать точки останова в классе StaticCache методе GetSuppliers().

Кэшированные данные поставщика отображаются в GridView

Рис. 7. Кэшированные данные поставщика отображаются в GridView (щелкните, чтобы просмотреть изображение полного размера)

Сводка

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

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

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

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

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

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

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