Упрощение процесса создания приложений для базы данных

Повторная задержка выхода SQL Server 2005 и Visual Studio 2005 предоставила администраторам баз данных (DBA) и разработчикам дополнительное время для того, чтобы поработать с бета-версиями обоих продуктов, а также осмыслить то, как обновленные инструментальные средства могут изменить сам процесс создания приложений. Я очень рекомендую начать использовать новые возможности при проектировании и планировании приложений прямо сейчас, не дожидаясь выхода официальных версий. Это позволит получить приложения, которые сразу смогут использовать все преимущества, обеспечиваемые новыми продуктами.

Теперь в распоряжении разработчиков появилась масса новых возможностей, поэтому перед клиентами может возникнуть проблема выбора: что задействовать первую очередь? Позволю себе обратить внимание читателей на три компонента расширения SQL Server 2005 и Visual Studio 2005, которые были разработаны специально для обеспечения эффективного и надежного совместного функционирования этих двух продуктов. Я имею в виду новый компонент Multiple Active Result Sets (MARS), интегрированную среду .NET Common Language Runtime (CLR), а также обновление пространства имен транзакций (transaction namespace). Каждое из этих расширений по-своему влияет на процесс разработки приложений. В частности, MARS обеспечивает улучшение масштабируемости за счет снижения количества необходимых соединений, интегрированная среда CLR предоставляет разработчикам и DBA возможности безопасного расширения функциональности их баз данных и, наконец, обновленное пространство имен транзакций превращает автоматические транзакции в действительно автоматические. Эти инструменты создавались для того, чтобы разработчики могли строить приложения с еще более гибкими возможностями, а администраторы DBA, в свою очередь, могли осуществлять поддержку приложений, используя обновленные возможности баз данных, а не просто манипулируя набором строк. Давайте рассмотрим, что дает нам каждая из этих новых возможностей для создания современных приложений.

Рассмотренные в статье примеры работают с Visual Studio 2005 Beta 2 и SQL Server 2005 Beta 3 и используют тестовую базу данных Adventure Works, которая поставляется вместе с SQL Server 2005. Для упрощения настройки строки соединения SQL Server 2005 и Visual Studio 2005 были установлены на один и тот же компьютер. Для того чтобы сделать эти примеры более функциональными, я приведу несколько хранимых процедур и некоторые дополнительные данные. Все это можно установить на стандартную базу AdventureWorks, воспользовавшись программой, код которой показан в листинге 1.

Путешествие на MARS

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

Самое интересное, что эта новая функциональность не требует установки сервера (хотя необходимо изменение подхода разработчика к использованию команд для реляционных баз данных). Несколько досадно, правда, что применение этих возможностей ограничивается только средой SQL Server 2005, поэтому, если в компании разрабатывается некий программный код с использованием парадигмы MARS, следует понимать, что база данных при этом должна находиться в SQL Server 2005.

Преимущества MARS касаются не только производительности и масштабируемости: при использовании этой технологии упрощается и код разрабатываемых программных средств. На листинге 2 меткой A обозначен фрагмент кода, создающий один объект соединения (connection), который затем использует команды чтения (reader) и обновления (update). Когда выполняется операция чтения и извлекаются данные по каждой строке, для них сразу же выполняется операция обновления. Весь этот процесс происходит в пределах одного соединения. Если попытаться одновременно организовать доступ к данным и их обновление в среде Visual Studio 2003 или SQL Server 2000, важно убедиться, что этот тип простого последовательного обновления, основанный на использовании курсоров на стороне сервера, работать не будет. Необходимо также учесть, что, если вы захотите откомпилировать код листинга 2 в Visual Studio 2003, перед этим из него следует убрать транзакционную логику, свойственную Visual Studio 2005.

CLR в SQL Server

Если MARS представляет собой расширение, по поводу которого было не слишком много шума и которое не требует настройки, то CLR — совсем другое дело. Интеграция CLR в SQL Server 2005 была, пожалуй, наиболее спорным вопросом, касающимся расширения SQL Server. Но в то же время это, наверное, одно из самых значительных усовершенствований. Основные сомнения по поводу CLR были связаны с тем, чтобы понять, когда его использовать, а когда нет.

Необходимо отметить, что CLR в SQL Server не является заменой T-SQL. И хотя из маркетинговой информации Microsoft следует, что теперь нужно использовать только языки .NET, на презентациях для технических специалистов нередко говорят о том, что в большинстве запросов применение T-SQL пока является более эффективным, чем использование CLR. С помощью этих двух, казалось бы, противоположных позиций техническая служба Microsoft хочет дать четкие рекомендации о том, как правильно использовать CLR в SQL Server 2005, а не внушить клиентам опасения по поводу CLR.

По сравнению с T-SQL, язык CLR имеет ряд специфических преимуществ. Первое из них заключается в возможности создания функций, которые производят интенсивную обработку. С помощью CLR можно создавать функции, которые инкапсулируют некоторые бизнес-вычисления внутри базы данных. Если такие функции используются именно для вычислений (а не для извлечения данных), то в этом случае использование CLR обеспечит выигрыш в производительности относительно T-SQL. Еще одним преимуществом применения CLR в SQL Server является то, что он может обрабатывать сложные конструкции XML. Кроме того, CLR позволяет создавать нестандартные типы, определяемые пользователем (User Defined Type, UDT). И последнее: использование CLR позволит отказаться от существовавших ранее и небезопасных расширенных хранимых процедур. В отличие от расширенных хранимых процедур, выполнение которых могло выходить из-под контроля SQL Server, CLR по умолчанию настроен так, что гарантируется выполнение используемых расширений T-SQL в текущем контексте безопасности. А сейчас рассмотрим, как можно создавать нестандартные UDT для дальнейшего использования в приложении.

Поскольку для нормального функционирования баз данных не требуются какие-либо механизмы CLR, по умолчанию в SQL Server 2005 компонент CLR отключен. Поэтому, для того чтобы задействовать возможности CLR, прежде всего его нужно включить. Для этого требуется открыть окно Query в SQL Management Studio и перенести туда приведенную ниже команду запуска стандартной хранимой процедуры T-SQL sp_configure.

sp_configure 'CLR Enabled', 1
GO
RECONFIGURE
EXEC sp_configure

Данная инструкция T-SQL включает механизм CLR и возвращает текущие параметры конфигурации базы данных. Более подробная информация о команде sp_configure содержится в документации Microsoft.

После включения CLR можно приступать к созданию UDT с помощью Visual Studio 2005. Соответствующий код может быть реализован как на Visual Basic, так и на C#, в данном примере я воспользовался Visual Basic. Сначала создается новый проект, для этого из списка типов проектов Visual Basic выбирается шаблон SQL Server Project. После присвоения проекту имени (я назвал его SQLServerUDT) Visual Studio попросит добавить ссылку на базу данных (соответствующее диалоговое окно приведено на экране 1). В данном диалоговом окне необходимо указать имя провайдера (в нашем примере требуется .NET Framework Data Provider for SQL Server). Затем в диалоговом окне New Database Reference (экран 2) нужно указать базу данных соответствующего проекта. Ввод значения local в текстовое поле Server name указывает на локальный SQL Server 2005, установленный на данном компьютере, который Visual Studio затем ассоциирует с соответствующим проектом.

Экран 1. Добавление ссылки на базу данных
Экран 2. Выбор базы данных для проекта

Итак, новый проект создан, теперь можно добавить класс, представляющий наш UDT. Следует щелкнуть на проекте правой кнопкой мыши и выбрать из контекстного меню пункт Add User Defined Type. Откроется новое диалоговое окно, содержащее несколько типов классов, которые могут быть добавлены в данный проект. Необходимо выбрать установленный по умолчанию класс User Defined Type и изменить заданное по умолчанию имя файла на myPointType.vb. После нажатия OK будет сгенерирован код, показанный в листинге 3.

Здесь видно, что код, сгенерированный для данного класса используемым по умолчанию шаблоном, содержит в самом низу описания частных (private) свойств этого нового класса. Я не буду здесь подробно останавливаться на том, как реализовать указатель типа, достаточно знать, что он состоит из двух целых чисел, которые с помощью данного UDT могут быть сохранены как одно значение. В листинге 4 показано, как выглядит исходный файл myPointType.vb после того, как указателю типа было дано это простое определение. Обратите внимание, что стандартная реализация дополнена компонентом Regions, который допускает свертывание, таким образом, можно группировать связанные друг с другом части при реализации данного типа.

Теперь, когда у нас есть созданный обновленный класс, следующий шаг - компиляция данного класса. В результате будет создан файл c расширением .DLL, доступный для любого из проектов, в котором используется ссылка на созданный нами тип, но для этого сначала нужно разместить новый тип в SQL Server. Это можно сделать двумя способами. Для разрабатываемой базы данных (но не для промышленно эксплуатируемой) можно использовать функцию Deploy пакета Visual Studio. Для этого нужно перейти в меню Build, выбрать пункт Deploy, и Visual Studio автоматически скомпилирует ваш UDT и разместит его в той базе данных SQL Server, на которую была ссылка.

Второй метод размещения UDT пригоден как для разрабатываемых, так и для промышленных баз данных и состоит в использовании команд T-SQL. Последовательность команд T-SQL, используемая для установки созданного UDT на SQL Server, приведена в листинге 5. Здесь указан путь к каталогу, соответствующий моему локальному компьютеру, перед запуском команд на другой машине необходимо соответствующим образом изменить описание пути. Для того чтобы распознавать данный тип, SQL Server и имеющееся приложение должны ссылаться на эту сборку.

Чтобы воспользоваться вновь созданным типом, нужно сделать ссылку на него, а затем создать параметр для хранимой процедуры типа UDT.

' Создание параметра для типа UDT.
Dim paramUDT = 
updateCommand.Parameters.Add("@v",
 SqlDbType.Udt)
paramUDT.UdtTypeName = "myPointType";
paramUDT.Value = new myPointType(4, 22);

Итак, это было краткое введение, позволяющее усвоить основные принципы создания с помощью .NET CLR нестандартного UDT, который будет распознаваться и вашей базой данных, и созданным приложением. По мере накопления опыта работы с CLR вы научитесь использовать возможности XML для дальнейшего расширения функциональности создаваемых типов.

Усовершенствование механизма распределенных транзакций

При работе с .NET и подключении к SQL Server с помощьюVisual Studio более ранней версии, чем 2005, и одновременном требовании, чтобы транзакция затрагивала несколько источников данных (этот механизм также известен как автоматическая транзакция), придется сначала разместить компоненты .NET в пространстве имен Enterprise Services .NET, а затем интегрировать сборки .NET с COM+. С выпуском Visual Studio 2005 этот процесс упростился, что обусловлено появлением нового пространства имен, называемого System.Transactions. (Данное пространство имен описывается в документации Microsoft, доступной по адресу: http://msdn2.microsoft.com/library/ system.transactions.aspx или в MSDN в разделе .NET Framework Class Library.) Для управления транзакциями разработчики могут использовать три основных класса пространства System.Transactions. К ним относятся Transaction, TransactionScope и TransactionManager.

В среде .NET 1.1 для вызова метода BeginTransaction используется объект Connection. Если задействовать этот метод в случае соединения с SQL Server, то объект Connection возвратит объект System.Data.SqlClient.SqlTransaction. Этот объект затем может быть ассоциирован с каждой из команд, являющейся составной частью данной транзакции. Повторные вызовы, выполняемые SQL Server, все равно производят неявные транзакции, поэтому объект, соответствующий транзакции, нужен лишь для того, чтобы объединить в одну группу несколько команд.

Когда вызывается метод Begin Transaction, ADO.NET использует для обращения к SQL Server существующее соединение и запускает на исполнение команду T-SQL Begin Transaction. Таким образом, чтобы использовать метод BeginTransaction, нужно последовательно обращаться к одному и тому же объекту, соответствующему соединению, для каждой команды, являющейся частью данной транзакции, причем данный тип транзакций несовместим с транзакциями COM+.

Первое, что следует уяснить относительно использования пространства имен System.Transactions, — это то, что можно по-прежнему создавать в SQL Server ручные транзакции и не прибегать к методу BeginTransaction. Созданная транзакция может по-прежнему считаться ручной, поскольку клиент не только программирует код ее начала и завершения, но и ассоциирует транзакцию с каждой из составляющих ее команд.

В Visual Studio 2005 появился объект System.Transactions.Transaction, с помощью которого можно вручную включать в транзакцию необходимые команды. В листинге 2 меткой B отмечен фрагмент кода, представляющий собой пример создания вручную объекта System. Transactions. CommittableTransaction. Объект CommittableTransaction представляет собой одну из реализаций виртуального базового класса Transaction. Сначала создается объект Connection, затем устанавливается соединение. После того как соединение с базой данных установлено, объект Connection использует объект CommitableTransaction для формирования транзакции. Эта точка является началом транзакции; начиная с нее можно выполнить одну или несколько команд работы с базой данных, которые будут являться частью данной транзакции. И наконец, в момент завершения обращения к базе данных мы можем либо выполнить (commit) либо отменить (roll back) нашу транзакцию.

На первый взгляд возможность ручной привязки нового объекта транзакции к соединению мало чем отличается от существующей логики транзакций, но на самом деле здесь в корне меняется сама парадигма транзакции. Код, обозначенный меткой B, создает действительно распределенную транзакцию, для чего в Visual Studio 2003 потребовалось бы использование Enterprise Services. А в рассматриваемом нами проекте нет ссылок на пространство имен System.EnterpriseServices. В Visual Studio 2005 для создания транзакций, использующих несколько источников данных, в раздел ссылок проекта необходимо включить только библиотеку System.Transactions. А если нет нужды обращаться к Enterprise Services, это означает, что код программ упрощается и нет необходимости интегрировать свою сборку с COM+. Теперь, находясь в среде .NET, можно создавать распределенные транзакции, использующие несколько соединений. Также необходимо помнить, что до завершения транзакции объект, соответствующий соединению, должен оставаться открытым (хотя он может быть при этом в «спящем» (dormant) состоянии), что иллюстрирует последовательность команд фрагмента кода рассматриваемого примера.

Конечно, с появлением объекта System.Transactions.Transaction процедура управления распределенными транзакциями упростилась, однако разработчики Visual Studio 2005 пошли еще дальше и предоставили нам инструментальные средства для автоматизации распределенных транзакций. Объект TransactionScope дает возможность автоматически ассоциировать с текущей транзакцией каждый объект соединения в пределах установленных границ (scope). Как видно из примера с меткой C в листинге 2, код с использованием объекта TransactionScope выглядит даже несколько проще, чем код для ручного создания объекта System.Transaction.Transaction. Код, обозначенный меткой C, начинается с нового элемента языка Visual Basic - команды Using. Объект TransactionScope всегда следует создавать в контексте команды Using, это гарантирует точное определение границ транзакции. После этого можно создать и установить столько соединений, сколько требуется, и каждая команда, выполняемая в контексте границ активной транзакции, будет автоматически ассоциирована с данной транзакцией.

В ходе выполнения фрагмента, обозначенного меткой C, создается несколько транзакций, но, поскольку в рассматриваемом примере используется только один источник данных, я оставил активным лишь одно соединение. В данном примере сначала устанавливается соединение и выполняется команда Update. На следующем шаге устанавливается статус транзакции. Обратите внимание на разницу между установкой статуса и выполнением транзакции. Когда пользователь работает с объектом TransactionScope, транзакция не будет выполняться до тех пор, пока программа не дойдет до предложения End Using. Вызовы методов Complete или Dispose на самом деле не завершают и не откатывают транзакцию. Они просто указывают на то, что произойдет, когда будет достигнута граница TransactionScope. Если вместо объекта Transaction используется объект TransactionScope, то в этом случае отпадает необходимость в ассоциировании различных соединений с данной транзакцией, это автоматически сделает .NET.

Третьим основным объектом пространства имен System.Transactions является объект TransactionManager. Данный объект проектировался не столько для обработки транзакций, сколько для предоставления разработчикам интерфейса к координатору распределенных транзакций, distributed-transaction coordinator. Описание работы с этим объектом выходит за рамки данной статьи, скажу лишь, что назначение этого объекта состоит в том, чтобы предоставить разработчикам набор статических методов, которые они могли бы использовать для доступа к одному или нескольким менеджерам транзакций. Таким образом, теперь разработчики могут регистрировать в системе утилиты управления транзакциями, отличные от тех, которые в .NET имеются по умолчанию, а это в свою очередь означает, что теперь можно расширить технологию координирования транзакций за рамки COM+.

Пора за работу

В данной статье мы рассмотрели только три новые возможности, которыми можно пользоваться при работе с SQL Server 2005 и Visual Studio 2005. В этих продуктах имеется еще масса механизмов для расширения функциональности создаваемых приложений. К ним относятся возможность работы с XML, создание по-настоящему асинхронных запросов к базе данных и усовершенствованная технология обработки ошибок. Одним словом, независимого от того, кто вы - разработчик или администратор, настало время начинать работать с этими продуктами. В качестве основы для новых разработок уже можно использовать финальные версии SQL Server 2005 и Visual Studio 2005.

Уильям Шелдон - Ведущий инженер компании InterKnowlogy, имеет сертификаты MCSD и MCP+SiteBuilding bsheldon@interknowlogy.com