Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral

Если в качестве второго параметра вы передаете значение EmptyParam, в состав результирующего набора данных включается вся информация указанного типа для всей базы данных. Очень часто для удобства вы хотите выполнить фильтрацию информации. Конечно же, для этой цели можно применить к результирующему набору данных традиционный фильтр Delphi (для этого можно использовать свойства Filter и Filtered или событие OnFilterRecord). Однако в этом случае фильтрация будет выполняться на стороне клиента. Второй параметр позволяет выполнить фильтрацию более эффективно на стороне источника информации о схеме. Фильтр определяется как массив значений. Каждый элемент массива обладает специальным смыслом, имеющим отношение к типу возвращаемых данных. Например, массив фильтров для первичных ключей включает в себя три элемента: каталог (то есть базу данных), схему и имя таблицы. Этот пример возвращает перечень первичных ключей в таблице Customer:
var Filter: OLEVAriant; begin Filter := VarArrayCreate([0, 2], varVariant); Filter[2] := 'CUSTOMER'; ADOConnection1.OpenSchema( siPrimaryKeys, Filter, EmptyParam, ADODataSet1); end; |
ПРИМЕЧАНИЕ
Ту же информацию можно получить при помощи ADOX. ADOX — это дополнительная технология ADO, которая позволяет вам получать и изменять информацию о схеме. В SQL эквивалентом ADOX является язык DDL (Data Definition Language), то есть выражения CREATE, ALTER, DROP и DCL (Data Control Language), то есть выражения GRANT, REVOKE. В рамках dbGo технология ADOX напрямую не поддерживается, однако вы можете импортировать библиотеку типов ADOX и использовать ее в приложениях Delphi. В отличие от метода OpenSchema, реализация ADOX в Delphi не универсальна, поэтому использовать ее не всегда удобно. Если вы хотите просто получить информацию о схеме, но не изменять ее, для этой цели, как правило, удобнее использовать метод OpenSchema.
[В начало]
Использование механизма Jet
Теперь, когда вы получили базовое представление об MDAC и ADO, мы можем перейти к рассмотрению механизма Jet. Для одних этот механизм представляет интерес, другим он совершенно не нужен. Если вы имеете дело с Access, Paradox, dBase, Excel, Lotus 1-2-3, HTML или данными, хранящимися в текстовых файлах, значит, рассматриваемый здесь материал будет для вас полезным. Если вы не заинтересованы в перечисленных здесь форматах, вы можете пропустить весь этот раздел.
Как правило, механизм Jet ассоциируется с базами данных Microsoft Access. Действительно, Access является основной системой, с которой взаимодействует Jet. Однако помимо Access механизм Jet позволяет работать с множеством других локальных источников данных. Многие не подозревают об этом, однако именно в этом заключается одно из основных преимуществ Jet. Взаимодействие с Access через Jet в стандартном режиме работы этого механизма выполняется относительно просто, поэтому здесь мы не будем рассматривать этот режим использования Jet. Вместо этого мы подробно рассмотрим взаимодействие Jet с другими форматами.
ПРИМЕЧАНИЕ
Механизм Jet входит в состав некоторых (но не всех) версий MDAC. В частности, он отсутствует в версии 2.6. В свое время было много споров относительно того, могут ли программисты, использующие средства разработки, не принадлежащие Microsoft, включать в комплект поставки своих программных продуктов механизм Jet. Официально считается, что такое возможно. Механизм Jet можно загрузить бесплатно с веб-узла компании Microsoft, кроме того, этот механизм входит в комплект поставки многих продуктов компании Microsoft.
Существует два провайдера OLE DB для механизма Jet: Jet 3.51 OLE DB и Jet 4.0 OLE DB. Провайдер Jet 3.51 OLE DB использует Jet 3.51 и поддерживает работу только с Access 97. Если вы будете применять только Access 97 и не собираетесь переходить на Access 2000, то Jet 3.51 в большинстве случаев даст более высокую производительность по сравнению с провайдером Jet 4.0 OLE DB.
Провайдер Jet 4.0 OLE DB поддерживает работу с Access 97, Access 2000 и с драйверами IISAM (Installable Indexed Sequential Access Method). Устанавливаемые драйверы ISAM специально написаны для механизма Jet и обеспечивают доступ к таким форматам, как Paradox, dBase и текстовые файлы. Именно возможность использования этих драйверов делает Jet полезным и удобным инструментом. Полный список драйверов ISAM, установленных на вашем компьютере, определяется набором установленного в системе программного обеспечения. Этот список располагается в реестре по адресу:
HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\ISAM Formats |
В состав комплекта поставки Jet входят драйверы для Paradox, dBase, Excel, текстовых файлов и HTML.
[В начало]
Импорт и экспорт
Механизм Jet удобно использовать для импорта и экспорта данных. Процесс экспортирования данных одинаков для каждого экспортированного формата и состоит из исполнения выражения SELECT в специальном формате. Рассмотрим пример экспортирования данных из базы данных Access в примере DBDemos в таблицу Paradox. Для этого добавим в программу JetImportExport активное соединение ADOConnection с названием ADOConnection1. Это соединение использует механизм Jet для того, чтобы открыть базу данных. Следующий код экспортирует таблицу Customer в файл Customer. db формата Paradox:
SELECT * INTO Customer IN "C:\tmp" "Paradox 7.x;" FROM CUSTOMER |
Рассмотрим составные части этого SQL-выражения. После ключевого слова INTO указывается новая таблица, которая будет создана в результате выполнения оператора SELECT. До выполнения этого кода таблица с этим именем должна отсутствовать в базе. После ключевого слова IN указывается база данных, в которую добавляется новая таблица. В Paradox это должен быть каталог, который уже существует на диске. Сразу же после имени базы данных указывается имя драйвера IISAM, который будет использоваться для экспорта данных. В конце имени драйвера обязательно нужно добавить символ точки с запятой (;). Ключевое слово FROM является стандартным компонентом любого выражения SELECT. В рассматриваемом примере эта операция выполняется при помощи компонента ADOConnection1, вместо фиксированного имени каталога используется текущий каталог программы:
ADOConnection1.Execute (''SELECT * INTO Customer IN "' + CurrentFolder + '" "Paradox 7.x;" FROM CUSTOMER'); |
Точно такой же формат используется в любых операциях экспорта, однако в зависимости от используемого драйвера IISAM имя базы данных интерпретируется по-разному. Вот аналогичное выражение, которое экспортирует данные в таблицу Excel:
ADOConnection1.Execute ('SELECT * INTO Customer IN "' + CurrentFolder + 'dbdemos. xls" "Excel 8.0;" FROM CUSTOMER’); |
Новый файл Excel с именем dbdemos. xls создается в текущем каталоге программы. В этот документ Excel добавляется рабочая книга с именем Customer, в которую заносятся все данные из таблицы Customer базы данных Access с именем dbdemo. mdb.
Вот еще одно выражение, которое экспортирует те же самые данные в HTMLфайл:
ADOConnection1.Execute ('SELECT * INTO [customer. htm] IN "' + CurrentFolder + '" "HTML Export;" FROM CUSTOMER'); |
В данном случае база данных — это каталог (как и в Paradox). Имя таблицы включает в себя расширение. htm, поэтому имя таблицы необходимо заключить в квадратные скобки. Обратите внимание, что драйвер IISAM называется не просто HTML, а HTML Export. Как следует из названия, драйвер позволяет только экспортировать данные, но не позволяет импортировать их.
Наконец, давайте рассмотрим входящий в состав Jet драйвер HTML Import, который является полезным дополнением к HTML Export. Добавьте на форму компонент ADOTable. Настройте строку подключения ConnectionString на использование провайдера Jet 4.0 OLE DB. Присвойте параметру Extended Properties строки подключения значение HTML Import. В качестве имени базы данных укажите имя HTML-файла, который был создан в результате экспорта (чуть ранее), точнее говоря, Customer. htm. Теперь присвойте свойству TableName значение Customer. Откройте таблицу — вы только что импортировали данные из HTML-файла. Имейте в виду, что если вы попытаетесь обновить данные, система выдаст ошибку, так как драйвер предназначен только для импорта. Если вы создали собственный HTMLфайл, в котором содержатся таблицы, и хотите открыть эти таблицы с использованием данного драйвера, вы должны помнить, что имя таблицы — это значение тега caption в HTML-разделе table.
[В начало]
Работа с курсорами
У каждого из наборов данных ADO есть два свойства, которые неразрывно связаны друг с другом и оказывают значительное влияние на ваше приложение. Это свойства CursorLocation и CursorType. Если вы хотите понять принцип функционирования набора данных ADO, вы должны изучить эти два свойства.
[В начало]
Положение курсора (свойство CursorLocation)
Свойство CursorLocation определяет, каким образом осуществляется извлечение и модификация данных. Этому свойству можно присвоить одно из двух значений: clUseClient (курсор на стороне клиента) или clUseServer (курсор на стороне сервера). Выбор значения в большой степени влияет на функциональность, производительность и масштабируемость базы данных.
Клиентский курсор обслуживается механизмом ADO Cursor Engine. Этот механизм является превосходным примером провайдера обслуживания OLE DB: он обеспечивает обслуживание для других провайдеров OLDE DB. Механизм ADO Cursor Engine управляет обработкой данных на стороне клиента. При открытии набора данных все данные результирующего набора перекачиваются с сервера на клиентский компьютер. После этого данные хранятся в памяти, их обновление и обработка осуществляется с использованием ADO Cursor Engine. Этот подход напоминает использование ClientDataSet в приложениях dbExpress. Преимущество состоит в том, что после передачи данных на сторону клиента любые манипуляции с этими данными выполняются значительно быстрее. Кроме того, так как манипуляции выполняются в памяти, механизм ADO Cursor Engine обладает более широкими возможностями, чем любой из курсоров, работающих на стороне сервера. Далее я подробнее рассмотрю эти преимущества, а также другие технологии, основанные на клиентских курсорах (в частности, отключенные и постоянные наборы записей). Курсор на стороне сервера управляется самой системой RDBMS. В клиент-серверной архитектуре, основанной на таких продуктах, как SQL Server, Oracle или InterBase, это означает, что управление курсором осуществляется на удаленном серверном компьютере. Если речь идет о настольной базе данных, такой как Access или Paradox, серверный курсор управляется программным продуктом, обслуживающим базу данных. То есть логически курсор расположен на «сервере», однако физически база данных вместе с курсором располагается на клиентском компьютере. Как правило, серверные курсоры загружаются быстрее, чем клиентские курсоры, так как при открытии набора данных с серверным курсором нет необходимости перемещать все данные на сторону клиента. Благодаря этому серверные курсоры лучше подходят для обслуживания больших наборов данных, то есть тогда, когда клиентский компьютер не обладает объемом памяти, достаточным для хранения всего набора данных. Чтобы понять возможности курсоров обоих типов, лучше всего посмотреть, как они функционируют в той или иной ситуации. Например, можно взять ситуацию блокирования записей. Чуть позднее я более подробно расскажу о блокировании. (Если вы хотите заблокировать запись, вам потребуется серверный курсор, так как система RDBMS должна знать о том, что запись заблокирована.)
Еще одной характеристикой, на которую следует обратить внимание при выборе местоположения курсора, является масштабируемость. Серверные курсоры располагаются на стороне сервера. Чем больше пользователей подключается к базе, тем больше курсоров создается на сервере. С каждым новым курсором нагрузка на сервер возрастает. Таким образом, при увеличении количества пользователей общая производительность системы может существенно понизиться. Используя курсоры на стороне клиента, вы можете существенно повысить масштабируемость вашего приложения. Открытие клиентского курсора обойдется вам дороже, так как в процессе открытия все данные передаются на сторону клиента, однако обслуживание клиентского курсора менее обременительно для сервера, ведь основная связанная с этим нагрузка возлагается на клиентский компьютер.
[В начало]
Тип курсора (свойство CursorType)
Тип курсора во многом определяется местом расположения курсора. Существует пять типов курсоров, один из которых не используется. Неиспользуемый тип называется unspecified (неуказанный). В ADO существует много значений, которые соответствуют неуказанному значению. В Delphi эти значения фактически никогда не используются. Эти значения присутствуют в Delphi только потому, что они присутствуют в ADO. Дело в том, что технология ADO изначально разрабатывалась для таких языков, как Visual Basic и C. В этих языках вы работаете с объектами напрямую, без поддержки вспомогательных механизмов, таких как dbGo. В результате вы можете создать открытый набор записей (в терминологии ADO — recordset), не указывая при этом значения для каждого из свойств. Таким образом, значения некоторых свойств будут не определены. В этом случае свойству присваивается значение unspecified (не указано). Однако в рамках dbGo вы имеете дело с компонентами. Компоненты обладают конструкторами. Конструктор — это функция, которая в обязательном порядке инициализирует каждое из свойств компонента. Когда вы создаете компонент dbGo, каждое из его свойств обладает определенным значением. В итоге отпадает надобность в использовании значения unspecified (не указано).
Тип курсора влияет на то, каким образом происходит чтение и обновление данных. Можно использовать один из четырех типов курсора: Forward-Only (только вперед), Static (статический), Keyset (набор ключей) и Dynamic (динамический). Прежде чем переходить к обсуждению разнообразных комбинаций типов и местоположения курсора, отмечу одно важное обстоятельство: для курсоров, работающих на стороне клиента, можно использовать только один тип: статический курсор. Все остальные типы курсоров могут использоваться только на стороне сервера. Давайте подробнее рассмотрим типы курсоров в порядке возрастания затрат, связанных с их обслуживанием.
· Forward-only (только вперед). Курсоры этого типа обходятся дешевле всего в смысле затрат. Иными словами, такие курсоры обеспечивают самую высокую производительность. Как следует из имени, курсор Forward-only (только вперед) позволяет вам перемещаться по набору данных в направлении от начала к концу. Курсор читает с сервера количество записей, указанное в свойстве CacheSize (по умолчанию 1), каждый раз, как только он покидает последнюю запись в локальном кэше, он читает с сервера следующую порцию записей. Любая попытка переместиться по направлению к началу набора записей за пределы локального кэша приводит к возникновению ошибки. Это поведение напоминает поведение набора данных в библиотеке dbExpress. Курсор Forwardonly (только вперед) плохо подходит для формирования пользовательского интерфейса, в котором пользователь обладает возможностью контролировать направление перемещения. Вместе с тем, такой курсор вполне подходит для выполнения пакетных операций, формирования отчетов, при построении вебприложений, не сохраняющих информацию о состоянии, — в любой из этих ситуаций вы начинаете с начала набора данных и перемещаетесь по направлению к концу набора данных. По достижении конца набор данных закрывается.
· Static (статический). При использовании статического курсора набор данных полностью перемещается на сторону клиента, обращение к нему осуществляется при помощи окна размером CacheSize. В результате пользователь получает возможность перемещаться по набору данных в обоих направлениях. Недостаток заключается в том, что данные являются статическими — обновления, добавления и удаления записей, выполняемые другими пользователями, не видны для статического курсора, так как данные курсора уже прочитаны.
· Keyset (набор ключей). Чтобы понять принцип функционирования этого курсора, разделите слово Keyset на две части: key и set. Key — это ключ, то есть в данном контексте — идентификатор записи. Зачастую имеется в виду первичный ключ. Set — это множество или набор. Получается «набор ключей». При открытии набора данных с сервера читается полный список всех ключей. Например, если набор данных формируется при помощи выражения SELECT * FROM CUSTOMER, значит, список ключей можно сформировать при помощи выражения SELECT CUSTID FROM CUSTOMER. Набор ключей хранится на стороне клиента до закрытия курсора. Когда приложение нуждается в данных, провайдер OLE DB читает строки таблицы, используя для этой цели имеющийся у него набор ключей. В результате клиент всегда имеет дело с обновленными данными. Однако набор ключей является статическим в том смысле, что после открытия курсора в этот набор нельзя добавить новые ключи, также ключи нельзя удалить из набора. Иными словами, если другой пользователь добавляет в таблицу новые записи, эти изменения не будут видны для клиента. Удаленные записи становятся недоступными, а любые изменения в первичных ключах (как правило, пользователям запрещается менять первичные ключи) также становятся недоступными.
· Dynamic (динамический). Это наиболее дорогостоящий курсор. Динамический курсор функционирует приблизительно так же, как курсор набора ключей. Разница заключается в том, что набор ключей заново читается с сервера каждый раз, когда приложение нуждается в данных, отсутствующих в кэше. Так как значение свойства ADODataSet. CacheSize по умолчанию равно 1, запросы на чтение данных возникают достаточно часто. Можно себе представить дополнительную нагрузку, которую данный курсор создает на сервер DBMS и на сеть. Однако при использовании этого курсора клиент знает не только об изменениях данных, но и о добавлениях и удалениях, выполняемых другими клиентами.
[В начало]
Вы не всегда получаете то, о чем просите
Теперь, когда вы знаете о типах и местоположении курсора, я должен предупредить вас о том, что допускается использование далеко не всех комбинаций типов и местоположений курсора. Как правило, это ограничение связано с типом RDBMS и/или провайдером OLE DB. Например, если курсор располагается на стороне клиента, тип курсора может быть только статическим. Вы можете понаблюдать подобное поведение самостоятельно. Добавьте на форму компонент ADODataSet, настройте свойство ConnectionString для подключения к любой базе данных, после этого присвойте свойству ClientLocation значение clUseCursor, а свойству CursorType — значение ctDynamic. Теперь измените значение свойства Active на True и понаблюдайте за свойством CursorType. Значение этого свойства немедленно изменится на ctStatic. Следует сделать важный вывод: вы далеко не всегда получаете именно то, о чем просите. Открыв набор данных, всегда проверяйте значения свойств — некоторые из них могут самопроизвольно изменить свои значения. Для различных провайдеров OLE DB характерны разные изменения свойств. Приведу лишь несколько примеров:
· провайдер Jet 4.0 OLE DB изменяет большинство типов курсоров на Keyset (набор ключей);
· провайдер SQL Server OLE DB часто меняет Keyset (набор ключей) и Static (статический) на Dynamic (динамический);
· провайдер Oracle OLE DB меняет все типы курсоров на Forward-only (только вперед);
· провайдер ODBC OLE DB может выполнить самые разные изменения типа курсора в зависимости от используемого драйвера ODBC.
[В начало]
Отсутствие счетчика
Когда вы пытаетесь прочитать свойство RecordCount какого-либо набора данных ADO, иногда вы обнаруживаете, что это свойство равно –1. Курсор типа Forwardonly не знает, какое количество записей входит в состав набора данных, пока он не достигнет конца набора. По этой причине свойство RecordCount равно значению – 1. Статический курсор всегда знает, какое количество записей входит в набор данных, так как статический курсор читает все данные набора в момент открытия. Курсор типа Keyset (набор ключей) тоже знает количество записей в наборе, так как в момент открытия набора данных он извлекает из базы данных фиксированный набор ключевых значений. Таким образом, для курсоров Static и Keyset вы можете обратиться к свойству RecordCount и получить точное количество записей в наборе. Динамический курсор не может достоверно знать количество записей, так как каждый раз при чтении данных он заново читает набор ключей, поэтому свойство RecordCount для этого курсора всегда равно –1. Вы можете вообще отказаться от использования свойства RecordCount и вместо этого использовать выражение SELECT COUNT(*) FROM имя_таблицы. Однако в результате вы получите неточное значение количества записей в таблице базы данных — это значение далеко не всегда совпадает с количеством записей в наборе данных.
[В начало]
Клиентские индексы
Одним из преимуществ курсоров, работающих на стороне клиента, является возможность создания локальных, или клиентских, индексов. Представьте, что у вас есть набор данных ADO с клиентским курсором и что этот набор соединен с таблицей Customer из примера DBDemos. Представьте, что к этому набору подключена сетка DBGrid. Присвойте свойству IndexFieldNames значение CompanyName. Сетка немедленно отобразит записи, упорядочив их в соответствии со значением поля CompanyName. Важно отметить, что для формирования индекса ADO не читает заново данные из источника. Индекс формируется на основе данных, хранящихся в памяти. Благодаря этому, во-первых, индекс формируется достаточно быстро, во-вторых, не создается никакой дополнительной нагрузки на сеть и DBMS. В противном случае одни и те же данные пришлось бы раз за разом передавать через сеть в различном порядке сортировки.
Свойство IndexFieldNames обладает еще кое-какими интересными возможностями. Например, присвойте этому свойству значение Country;CompanyName — вы увидите, что записи сначала отсортированы в соответствии с именем страны, а затем — в соответствии с именем компании. Теперь присвойте свойству IndexField - Names значение CompanyName DESC (ключевое слово DESC должно быть написано заглавными буквами, но не desc или Desc). В результате записи будут отсортированы в порядке убывания значений.
Эта простая, но весьма мощная возможность позволяет вам решить одну из наиболее актуальных проблем, связанных с программированием БД. Пользователи любят задавать неизбежный и неприятный для программистов, но совершенно оправданный вопрос: «Могу ли я щелкнуть на заголовке столбца сетки для того, чтобы отсортировать мои данные?» Существует несколько способов решения этой проблемы. Например, вы можете воспользоваться стандартным (не поддерживающим работу с данными) элементом управления, таким как ListView, который поддерживает встроенный механизм сортировки. Кроме того, вы можете выполнить обработку события OnTitleClick компонента DBGrid и в рамках обработчика заново исполнять SQL-выражение SELECT, добавляя к нему подходящую команду ORDER BY. Однако любое из этих решений нельзя назвать в полной мере удовлетворительным. Если данные кэшируются на стороне клиента (мы уже обсуждали этот подход, когда говорили о компоненте ClientDataSet), вы можете воспользоваться индексом, сформированным в памяти клиентского компьютера. Добавьте следующий обработчик события OnTitleClick для сетки (полный исходный код входит в состав примера ClientIndexes):
procedure Tfrom1.DBGrid1TitleClick(Column: Tcolumn); begin if ADODataSet1.IndexFieldNames = Column. Field. FieldName then ADODataSet1.IndexFieldNames := Column. Field. FieldName + ' DESC' else ADODataSet1.IndexFieldNames := Column. Field. FieldName end; |
Этот простой код проверяет, построен ли текущий индекс на основе поля, которое соответствует столбцу сетки, на заголовке которого сделан щелчок. Если да, то на основе этого же поля строится новый индекс, но в нисходящем порядке. Если нет, то на основе столбца формируется новый индекс. Когда пользователь щелкает на заголовке столбца первый раз, записи сортируются в порядке увеличения значений. Когда пользователь щелкает на этом же столбце второй раз, записи сортируются в порядке уменьшения. Вы можете усовершенствовать этот обработчик таким образом, чтобы позволить пользователю щелкать на нескольких заголовках, удерживая нажатой клавишу Ctrl. При этом можно формировать более сложные индексы.
ПРИМЕЧАНИЕ
Все то же самое можно реализовать с использованием компонента ClientDataSet, однако этот компонент не поддерживает ключевого слова DESC, поэтому для сортировки в порядке уменьшения значений вам потребуется написать дополнительный код. Более того, при смене порядка сортировки компонент ClientDataSet будет заново формировать индекс — это ненужная и, возможно, медленная операция.
[В начало]
Клонирование
Технология ADO поддерживает множество интересных возможностей. Вы можете пожаловаться, что обилие возможностей приводит к увеличению размера исполняемого кода, который приходится устанавливать на клиентском компьютере. Однако благодаря обилию возможностей ADO вы можете формировать мощные и надежные приложения. Одной из удобных возможностей ADO является возможность клонирования. Клонированный набор записей — это новый набор записей, который обладает точно таким же набором свойств, как и изначальный. Вначале я объясню, как происходит клонирование, затем расскажу о том, зачем это надо.
ПРИМЕЧАНИЕ
Компонент ClientDataSet также поддерживает клонирование, однако я не упомянул об этой возможности в главе 13.
Для клонирования набора данных (в ADO — набора записей) используется метод Clone. Клонировать можно любой набор данных ADO, однако в данном примере мы будет использовать компонент ADOTable. В программе DataClone (рис. 15.6) присутствуют два компонента ADOTable — один из них подключен к данным, а второй пуст. Оба набора данных подключены к источнику данных DataSource и сетке. Когда пользователь щелкает на кнопке Clone Dataset (клонировать набор данных), выполняется всего одна строка кода, которая клонирует набор данных:
ADOTable2.Clone(ADOTable1); |

Эта строка клонирует набор данных ADOTable1 и размещает полученный клон в наборе данных ADOTable2. Благодаря этому вы получаете два представления одних и тех же данных. Каждый набор обладает собственным указателем на текущую запись и собственной копией информации о состоянии, благодаря этому клон никак не влияет на изначальную копию данных. Подобное поведение делает клоны отличным инструментом работы с набором данных, не влияя при этом на изначальные данные. Еще одна интересная возможность: вы можете создать несколько разных активных записей — у разных клонов активные записи могут быть разными. Подобную функциональность нельзя реализовать в Delphi, используя лишь один набор данных.
СОВЕТ
Набор данных можно клонировать только в случае, если он поддерживает закладки (bookmarks). По этой причине курсоры типа «только вперед» и динамические курсоры не могут быть клонированы. Чтобы определить, поддерживает ли набор записей закладки, вы можете воспользоваться методом Supports (например, ADOTable1.Supports([coBookMark])). Побочный эффект клонирования заключается в том, что закладки, созданные одним из клонов, могут использоваться всеми остальными клонами.
[В начало]
Обработка транзакций
В разделе «Использование транзакций» главы 14 мы с вами говорили о том, что механизм транзакций позволяет разработчикам группировать отдельные операции в отношении БД в единую логически неразрывную процедуру.
Обработка транзакций в ADO осуществляется при помощи компонента ADOConnection, для этого используются методы BeginTrans, CommitTrans и RollbackTrans. Действие этих методов сходно с аналогичными методами dbExpress и BDE. Для изучения механизма транзакций, встроенного в ADO, воспользуемся программой TransProcessing. В состав программы входит компонент ADOConnection, строка подключения которого (свойство ConnectionString) настроена на использование провайдера Jet 4.0 OLE DB и на обращение к файлу dbdemos. mdb. В программе присутствует компонент ADOTable, подключенный к таблице Customer и связанный с компонентами DataSource и DBGrid для отображения данных. Наконец, в программе присутствуют три кнопки, предназначенные для выполнения следующих команд:
ADOConnection1.BeginTrans; ADOConnection1.CommitTrans; ADOConnection1.RollbackTrans; |
Используя эту программу, вы можете вносить в базу данных изменения, а затем выполнять откат транзакции, то есть отмену этих изменений. В результате база данных будет восстановлена в состояние, в котором она находилась до начала транзакции. Следует отметить, что обработка транзакций выполняется по-разному в зависимости от базы данных и провайдера OLE DB. Например, если вы подключитесь к Paradox с использованием провайдера ODBC OLE DB, вы получите сообщение об ошибке, указывающее на то, что база данных или провайдер OLE DB не могут начать транзакцию. Чтобы определить уровень поддержки транзакций, можно воспользоваться динамическим свойством Transaction DDL соединения:
if ADOConnection1.Properties['Transaction DDL'].Value > DBPROPVAL_TC_NONE then ADOConnection1.BeginTrans; |
Если вы попытаетесь обратиться к этой же базе данных Paradox при помощи провайдера Jet 4.0 OLE DB, никакой ошибки не возникнет, однако из-за ограничений провайдера вы не сможете выполнить откат транзакции.
Еще одно странное отличие проявляет себя при работе с Access: если вы используете провайдер ODBC OLE DB, вы сможете использовать транзакции, однако не сможете использовать вложенные транзакции. Попытка открыть новую транзакцию параллельно с уже существующей активной транзакцией приведет к возникновению ошибки. Однако при использовании механизма Jet вы сможете без проблем использовать вложенные транзакции.
[В начало]
Вложенные транзакции
Используя программу TransProcessing, попробуйте выполнить следующий тест.
1. Активизируйте транзакцию.
2. Измените значение поля ContactName записи Around The Horn: вместо Thomas Hardy поставьте Dick Solomon.
3. Активизируйте еще одну, вложенную транзакцию.
4. Измените значение поля ContactName записи Bottom-Dollar Markets: вместо Elizabeth Lincoln поставьте Sally Solomon.
5. Выполните откат внутренней транзакции.
6. Подтвердите внешнюю транзакцию.
В результате модификации должны быть внесены только в запись Around The Horn. Если же внутренняя транзакция будет подтверждена, а в отношении внешней транзакции вы выполните откат, в результате в базу данных вообще не будет внесено ни одного изменения (даже изменения, сделанные в рамках внутренней транзакции). Именно так работают вложенные транзакции. Существует ограничение: Access поддерживает только пять уровней вложения транзакций.
ODBC не поддерживает вложенных транзакций, а провайдер Jet OLE DB поддерживает до пяти уровней вложения. Провайдер SQL Server OLE DB вообще не поддерживает вложения транзакций. Вы должны иметь в виду, что вложение транзакций может обрабатываться по-разному в зависимости от версии SQL-сервера или драйвера. Необходимую информацию можно получить в документации и при помощи экспериментов. Судя по всему, в большинстве случаев внешняя транзакция определяет, будут ли внесены в базу данных изменения, сделанные в рамках внутренней транзакции.
[В начало]
Атрибуты компонента ADOConnection
Если вы планируете использовать вложенные транзакции, существует еще одно обстоятельство, которое вы должны принимать во внимание. Компонент ADOConnection обладает свойством Attributes, которое определяет, каким образом ведет себя соединение в момент, когда транзакция подтверждается или выполняется ее откат. В свойстве Attributes хранится множество значений TXActAttributes, которое изначально пусто. Перечисление TXActAttributes включает в себя только два значения: xaCommitRetaining и xaAbortRetaining (иногда это значение ошибочно записывают как xaRollbackRetaining, так как с логической точки зрения это более правильное название). Если в свойстве Attributes присутствует атрибут xaCommitRetaining, в момент подтверждения транзакции автоматически открывается новая транзакция. Если в свойстве Attributes присутствует атрибут xaAbortRetaining, в момент отката транзакции автоматически открывается новая транзакция. Таким образом, если вы добавите в свойство Attributes оба этих атрибута, любые действия будут выполняться в рамках транзакции: в момент завершения очередной транзакции будет автоматически активизироваться следующая.
В большинстве случаев программисты предпочитают отказаться от работы в таком режиме и самостоятельно контролировать открытие транзакций, поэтомуданные атрибуты используются нечасто. Следует принимать во внимание особенности использования этих атрибутов совместно с вложенными транзакциями. Если вы создаете вложенную транзакцию и присваиваете свойству Attributes значение [xaCommitRetaining, xaAbortRetaining], внешняя транзакция никогда не будет завершена. Рассмотрим такую последовательность событий.
1. Начинается внешняя транзакция.
2. Начинается внутренняя транзакция.
3. Выполняется подтверждение или откат внутренней транзакции.
В соответствии с настройкой свойства Attributes автоматически начинается новая внутренняя транзакция.
Таким образом, внешняя транзакция может никогда не завершиться, так как внутренние транзакции неразрывно следуют одна за другой. Можно сделать вывод, что свойство Attributes и использование вложенных транзакций — это взаимоисключающие вещи.
[В начало]
Типы блокировки
Технология ADO поддерживает четыре различных подхода к блокированию данных для обновления: ltReadOnly, ltPessimistic, ltOptimistic и ltBatchOptimistic (существует также тип ltUnspecified, однако по изложенным ранее причинам этот тип в Delphi не используется). Для настройки режима блокировки используется свойство LockType. В данном разделе я коротко расскажу обо всех четырех способах блокировки. В последующих разделах о каждом из этих способов будет рассказано подробнее.
Значение ltReadOnly указывает на то, что данные предназначены только для чтения, — обновление невозможно. Так как клиент не может выполнить модификацию данных, никакой блокировки не требуется.
Значения ltPessimistic и ltOptimistic обеспечивают пессимистическую и оптимистическую блокировку соответственно. Эти режимы являются эквивалентами аналогичных режимов BDE. Однако по сравнению с BDE технология ADO обеспечивает большую гибкость: выбор режима блокировки остается за вами. Если вы используете BDE, решение об использовании пессимистической или оптимистической блокировки выполняет за вас драйвер BDE. Если вы используете настольную базу данных, такую как Paradox или dBase, значит, драйвер BDE использует пессимистическую блокировку. Если вы используете клиент-серверную базу данных, такую как InterBase, SQLServer или Oracle, драйвер BDE использует оптимистическую блокировку.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 |


